00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <config.h>
00010
00011 #include "kmreaderwin.h"
00012
00013 #include "globalsettings.h"
00014 #include "kmversion.h"
00015 #include "kmmainwidget.h"
00016 #include "kmreadermainwin.h"
00017 #include <libtdepim/tdefileio.h>
00018 #include "kmfolderindex.h"
00019 #include "kmcommands.h"
00020 #include "kmmsgpartdlg.h"
00021 #include "mailsourceviewer.h"
00022 using KMail::MailSourceViewer;
00023 #include "partNode.h"
00024 #include "kmmsgdict.h"
00025 #include "messagesender.h"
00026 #include "kcursorsaver.h"
00027 #include "kmfolder.h"
00028 #include "vcardviewer.h"
00029 using KMail::VCardViewer;
00030 #include "objecttreeparser.h"
00031 using KMail::ObjectTreeParser;
00032 #include "partmetadata.h"
00033 using KMail::PartMetaData;
00034 #include "attachmentstrategy.h"
00035 using KMail::AttachmentStrategy;
00036 #include "headerstrategy.h"
00037 using KMail::HeaderStrategy;
00038 #include "headerstyle.h"
00039 using KMail::HeaderStyle;
00040 #include "tdehtmlparthtmlwriter.h"
00041 using KMail::HtmlWriter;
00042 using KMail::KHtmlPartHtmlWriter;
00043 #include "htmlstatusbar.h"
00044 using KMail::HtmlStatusBar;
00045 #include "folderjob.h"
00046 using KMail::FolderJob;
00047 #include "csshelper.h"
00048 using KMail::CSSHelper;
00049 #include "isubject.h"
00050 using KMail::ISubject;
00051 #include "urlhandlermanager.h"
00052 using KMail::URLHandlerManager;
00053 #include "interfaces/observable.h"
00054 #include "util.h"
00055 #include "kmheaders.h"
00056
00057 #include "broadcaststatus.h"
00058
00059 #include <kmime_mdn.h>
00060 using namespace KMime;
00061 #ifdef KMAIL_READER_HTML_DEBUG
00062 #include "filehtmlwriter.h"
00063 using KMail::FileHtmlWriter;
00064 #include "teehtmlwriter.h"
00065 using KMail::TeeHtmlWriter;
00066 #endif
00067
00068 #include <kasciistringtools.h>
00069 #include <kstringhandler.h>
00070
00071 #include <mimelib/mimepp.h>
00072 #include <mimelib/body.h>
00073 #include <mimelib/utility.h>
00074
00075 #include <kleo/specialjob.h>
00076 #include <kleo/cryptobackend.h>
00077 #include <kleo/cryptobackendfactory.h>
00078
00079
00080 #include <tdeabc/addressee.h>
00081 #include <tdeabc/vcardconverter.h>
00082
00083
00084 #include <tdehtml_part.h>
00085 #include <tdehtmlview.h>
00086 #include <dom/html_element.h>
00087 #include <dom/html_block.h>
00088 #include <dom/html_document.h>
00089 #include <dom/dom_string.h>
00090 #include <dom/dom_exception.h>
00091
00092 #include <tdeapplication.h>
00093
00094 #include <kuserprofile.h>
00095 #include <kcharsets.h>
00096 #include <tdepopupmenu.h>
00097 #include <kstandarddirs.h>
00098 #include <kcursor.h>
00099 #include <kdebug.h>
00100 #include <tdefiledialog.h>
00101 #include <tdelocale.h>
00102 #include <tdemessagebox.h>
00103 #include <tdeglobalsettings.h>
00104 #include <krun.h>
00105 #include <tdetempfile.h>
00106 #include <kprocess.h>
00107 #include <kdialog.h>
00108 #include <tdeaction.h>
00109 #include <kiconloader.h>
00110 #include <kmdcodec.h>
00111 #include <kasciistricmp.h>
00112 #include <kurldrag.h>
00113
00114 #include <tqclipboard.h>
00115 #include <tqhbox.h>
00116 #include <tqtextcodec.h>
00117 #include <tqpaintdevicemetrics.h>
00118 #include <tqlayout.h>
00119 #include <tqlabel.h>
00120 #include <tqsplitter.h>
00121 #include <tqstyle.h>
00122
00123
00124 #undef Never
00125 #undef Always
00126
00127 #include <unistd.h>
00128 #include <stdlib.h>
00129 #include <sys/stat.h>
00130 #include <errno.h>
00131 #include <stdio.h>
00132 #include <ctype.h>
00133 #include <string.h>
00134
00135 #ifdef HAVE_PATHS_H
00136 #include <paths.h>
00137 #endif
00138
00139 class NewByteArray : public TQByteArray
00140 {
00141 public:
00142 NewByteArray &appendNULL();
00143 NewByteArray &operator+=( const char * );
00144 NewByteArray &operator+=( const TQByteArray & );
00145 NewByteArray &operator+=( const TQCString & );
00146 TQByteArray& qByteArray();
00147 };
00148
00149 NewByteArray& NewByteArray::appendNULL()
00150 {
00151 TQByteArray::detach();
00152 uint len1 = size();
00153 if ( !TQByteArray::resize( len1 + 1 ) )
00154 return *this;
00155 *(data() + len1) = '\0';
00156 return *this;
00157 }
00158 NewByteArray& NewByteArray::operator+=( const char * newData )
00159 {
00160 if ( !newData )
00161 return *this;
00162 TQByteArray::detach();
00163 uint len1 = size();
00164 uint len2 = tqstrlen( newData );
00165 if ( !TQByteArray::resize( len1 + len2 ) )
00166 return *this;
00167 memcpy( data() + len1, newData, len2 );
00168 return *this;
00169 }
00170 NewByteArray& NewByteArray::operator+=( const TQByteArray & newData )
00171 {
00172 if ( newData.isNull() )
00173 return *this;
00174 TQByteArray::detach();
00175 uint len1 = size();
00176 uint len2 = newData.size();
00177 if ( !TQByteArray::resize( len1 + len2 ) )
00178 return *this;
00179 memcpy( data() + len1, newData.data(), len2 );
00180 return *this;
00181 }
00182 NewByteArray& NewByteArray::operator+=( const TQCString & newData )
00183 {
00184 if ( newData.isEmpty() )
00185 return *this;
00186 TQByteArray::detach();
00187 uint len1 = size();
00188 uint len2 = newData.length();
00189 if ( !TQByteArray::resize( len1 + len2 ) )
00190 return *this;
00191 memcpy( data() + len1, newData.data(), len2 );
00192 return *this;
00193 }
00194 TQByteArray& NewByteArray::qByteArray()
00195 {
00196 return *((TQByteArray*)this);
00197 }
00198
00199
00200
00201
00202
00203 void KMReaderWin::objectTreeToDecryptedMsg( partNode* node,
00204 NewByteArray& resultingData,
00205 KMMessage& theMessage,
00206 bool weAreReplacingTheRootNode,
00207 int recCount )
00208 {
00209 kdDebug(5006) << TQString("-------------------------------------------------" ) << endl;
00210 kdDebug(5006) << TQString("KMReaderWin::objectTreeToDecryptedMsg( %1 ) START").arg( recCount ) << endl;
00211 if( node ) {
00212
00213 kdDebug(5006) << node->typeString() << '/' << node->subTypeString() << endl;
00214
00215 partNode* curNode = node;
00216 partNode* dataNode = curNode;
00217 partNode * child = node->firstChild();
00218 const bool bIsMultipart = node->type() == DwMime::kTypeMultipart ;
00219 bool bKeepPartAsIs = false;
00220
00221 switch( curNode->type() ){
00222 case DwMime::kTypeMultipart: {
00223 switch( curNode->subType() ){
00224 case DwMime::kSubtypeSigned: {
00225 bKeepPartAsIs = true;
00226 }
00227 break;
00228 case DwMime::kSubtypeEncrypted: {
00229 if ( child )
00230 dataNode = child;
00231 }
00232 break;
00233 }
00234 }
00235 break;
00236 case DwMime::kTypeMessage: {
00237 switch( curNode->subType() ){
00238 case DwMime::kSubtypeRfc822: {
00239 if ( child )
00240 dataNode = child;
00241 }
00242 break;
00243 }
00244 }
00245 break;
00246 case DwMime::kTypeApplication: {
00247 switch( curNode->subType() ){
00248 case DwMime::kSubtypeOctetStream: {
00249 if ( child )
00250 dataNode = child;
00251 }
00252 break;
00253 case DwMime::kSubtypePkcs7Signature: {
00254
00255
00256 bKeepPartAsIs = true;
00257 }
00258 break;
00259 case DwMime::kSubtypePkcs7Mime: {
00260
00261
00262 if ( child && curNode->encryptionState() != KMMsgNotEncrypted )
00263 dataNode = child;
00264 }
00265 break;
00266 }
00267 }
00268 break;
00269 }
00270
00271
00272 DwHeaders& rootHeaders( theMessage.headers() );
00273 DwBodyPart * part = dataNode->dwPart() ? dataNode->dwPart() : 0;
00274 DwHeaders * headers(
00275 (part && part->hasHeaders())
00276 ? &part->Headers()
00277 : ( (weAreReplacingTheRootNode || !dataNode->parentNode())
00278 ? &rootHeaders
00279 : 0 ) );
00280 if( dataNode == curNode ) {
00281 kdDebug(5006) << "dataNode == curNode: Save curNode without replacing it." << endl;
00282
00283
00284
00285
00286 if( headers ) {
00287 if( dataNode->parentNode() && !weAreReplacingTheRootNode ) {
00288 kdDebug(5006) << "dataNode is NOT replacing the root node: Store the headers." << endl;
00289 resultingData += headers->AsString().c_str();
00290 } else if( weAreReplacingTheRootNode && part && part->hasHeaders() ){
00291 kdDebug(5006) << "dataNode replace the root node: Do NOT store the headers but change" << endl;
00292 kdDebug(5006) << " the Message's headers accordingly." << endl;
00293 kdDebug(5006) << " old Content-Type = " << rootHeaders.ContentType().AsString().c_str() << endl;
00294 kdDebug(5006) << " new Content-Type = " << headers->ContentType( ).AsString().c_str() << endl;
00295 rootHeaders.ContentType() = headers->ContentType();
00296 theMessage.setContentTransferEncodingStr(
00297 headers->HasContentTransferEncoding()
00298 ? headers->ContentTransferEncoding().AsString().c_str()
00299 : "" );
00300 rootHeaders.ContentDescription() = headers->ContentDescription();
00301 rootHeaders.ContentDisposition() = headers->ContentDisposition();
00302 theMessage.setNeedsAssembly();
00303 }
00304 }
00305
00306 if ( bKeepPartAsIs ) {
00307 resultingData += dataNode->encodedBody();
00308 } else {
00309
00310
00311 if( headers && bIsMultipart && dataNode->firstChild() ) {
00312 kdDebug(5006) << "is valid Multipart, processing children:" << endl;
00313 TQCString boundary = headers->ContentType().Boundary().c_str();
00314 curNode = dataNode->firstChild();
00315
00316 while( curNode ) {
00317 kdDebug(5006) << "--boundary" << endl;
00318 if( resultingData.size() &&
00319 ( '\n' != resultingData.at( resultingData.size()-1 ) ) )
00320 resultingData += TQCString( "\n" );
00321 resultingData += TQCString( "\n" );
00322 resultingData += "--";
00323 resultingData += boundary;
00324 resultingData += "\n";
00325
00326
00327
00328 objectTreeToDecryptedMsg( curNode,
00329 resultingData,
00330 theMessage,
00331 false,
00332 recCount + 1 );
00333 curNode = curNode->nextSibling();
00334 }
00335 kdDebug(5006) << "--boundary--" << endl;
00336 resultingData += "\n--";
00337 resultingData += boundary;
00338 resultingData += "--\n\n";
00339 kdDebug(5006) << "Multipart processing children - DONE" << endl;
00340 } else if( part ){
00341
00342 kdDebug(5006) << "is Simple part or invalid Multipart, storing body data .. DONE" << endl;
00343 resultingData += part->Body().AsString().c_str();
00344 }
00345 }
00346 } else {
00347 kdDebug(5006) << "dataNode != curNode: Replace curNode by dataNode." << endl;
00348 bool rootNodeReplaceFlag = weAreReplacingTheRootNode || !curNode->parentNode();
00349 if( rootNodeReplaceFlag ) {
00350 kdDebug(5006) << " Root node will be replaced." << endl;
00351 } else {
00352 kdDebug(5006) << " Root node will NOT be replaced." << endl;
00353 }
00354
00355
00356 objectTreeToDecryptedMsg( dataNode,
00357 resultingData,
00358 theMessage,
00359 rootNodeReplaceFlag,
00360 recCount + 1 );
00361 }
00362 }
00363 kdDebug(5006) << TQString("\nKMReaderWin::objectTreeToDecryptedMsg( %1 ) END").arg( recCount ) << endl;
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 void KMReaderWin::createWidgets() {
00388 TQVBoxLayout * vlay = new TQVBoxLayout( this );
00389 mSplitter = new TQSplitter( Qt::Vertical, this, "mSplitter" );
00390 vlay->addWidget( mSplitter );
00391 mMimePartTree = new KMMimePartTree( this, mSplitter, "mMimePartTree" );
00392 mBox = new TQHBox( mSplitter, "mBox" );
00393 setStyleDependantFrameWidth();
00394 mBox->setFrameStyle( mMimePartTree->frameStyle() );
00395 mColorBar = new HtmlStatusBar( mBox, "mColorBar" );
00396 mViewer = new TDEHTMLPart( mBox, "mViewer" );
00397 mSplitter->setOpaqueResize( TDEGlobalSettings::opaqueResize() );
00398 mSplitter->setResizeMode( mMimePartTree, TQSplitter::KeepSize );
00399 }
00400
00401 const int KMReaderWin::delay = 150;
00402
00403
00404 KMReaderWin::KMReaderWin(TQWidget *aParent,
00405 TQWidget *mainWindow,
00406 TDEActionCollection* actionCollection,
00407 const char *aName,
00408 int aFlags )
00409 : TQWidget(aParent, aName, aFlags | TQt::WDestructiveClose),
00410 mSerNumOfOriginalMessage( 0 ),
00411 mNodeIdOffset( -1 ),
00412 mAttachmentStrategy( 0 ),
00413 mHeaderStrategy( 0 ),
00414 mHeaderStyle( 0 ),
00415 mUpdateReaderWinTimer( 0, "mUpdateReaderWinTimer" ),
00416 mResizeTimer( 0, "mResizeTimer" ),
00417 mDelayedMarkTimer( 0, "mDelayedMarkTimer" ),
00418 mHeaderRefreshTimer( 0, "mHeaderRefreshTimer" ),
00419 mOldGlobalOverrideEncoding( "---" ),
00420 mCSSHelper( 0 ),
00421 mRootNode( 0 ),
00422 mMainWindow( mainWindow ),
00423 mActionCollection( actionCollection ),
00424 mMailToComposeAction( 0 ),
00425 mMailToReplyAction( 0 ),
00426 mMailToForwardAction( 0 ),
00427 mAddAddrBookAction( 0 ),
00428 mOpenAddrBookAction( 0 ),
00429 mCopyAction( 0 ),
00430 mCopyURLAction( 0 ),
00431 mUrlOpenAction( 0 ),
00432 mUrlSaveAsAction( 0 ),
00433 mAddBookmarksAction( 0 ),
00434 mStartIMChatAction( 0 ),
00435 mSelectAllAction( 0 ),
00436 mHeaderOnlyAttachmentsAction( 0 ),
00437 mSelectEncodingAction( 0 ),
00438 mToggleFixFontAction( 0 ),
00439 mCanStartDrag( false ),
00440 mHtmlWriter( 0 ),
00441 mSavedRelativePosition( 0 ),
00442 mDecrytMessageOverwrite( false ),
00443 mShowSignatureDetails( false ),
00444 mShowAttachmentQuicklist( true ),
00445 mShowRawToltecMail( false )
00446 {
00447 mExternalWindow = (aParent == mainWindow );
00448 mSplitterSizes << 180 << 100;
00449 mMimeTreeMode = 1;
00450 mMimeTreeAtBottom = true;
00451 mAutoDelete = false;
00452 mLastSerNum = 0;
00453 mWaitingForSerNum = 0;
00454 mMessage = 0;
00455 mMsgDisplay = true;
00456 mPrinting = false;
00457 mShowColorbar = false;
00458 mAtmUpdate = false;
00459
00460 createWidgets();
00461 createActions( actionCollection );
00462 initHtmlWidget();
00463 readConfig();
00464
00465 mHtmlOverride = false;
00466 mHtmlLoadExtOverride = false;
00467
00468 mLevelQuote = GlobalSettings::self()->collapseQuoteLevelSpin() - 1;
00469
00470 connect( &mUpdateReaderWinTimer, TQT_SIGNAL(timeout()),
00471 TQT_TQOBJECT(this), TQT_SLOT(updateReaderWin()) );
00472 connect( &mResizeTimer, TQT_SIGNAL(timeout()),
00473 TQT_TQOBJECT(this), TQT_SLOT(slotDelayedResize()) );
00474 connect( &mDelayedMarkTimer, TQT_SIGNAL(timeout()),
00475 TQT_TQOBJECT(this), TQT_SLOT(slotTouchMessage()) );
00476 connect( &mHeaderRefreshTimer, TQT_SIGNAL(timeout()),
00477 TQT_TQOBJECT(this), TQT_SLOT(updateHeader()) );
00478
00479 }
00480
00481 void KMReaderWin::createActions( TDEActionCollection * ac ) {
00482 if ( !ac )
00483 return;
00484
00485 TDERadioAction *raction = 0;
00486
00487
00488 TDEActionMenu *headerMenu =
00489 new TDEActionMenu( i18n("View->", "&Headers"), ac, "view_headers" );
00490 headerMenu->setToolTip( i18n("Choose display style of message headers") );
00491
00492 connect( headerMenu, TQT_SIGNAL(activated()),
00493 TQT_TQOBJECT(this), TQT_SLOT(slotCycleHeaderStyles()) );
00494
00495 raction = new TDERadioAction( i18n("View->headers->", "&Enterprise Headers"), 0,
00496 TQT_TQOBJECT(this), TQT_SLOT(slotEnterpriseHeaders()),
00497 ac, "view_headers_enterprise" );
00498 raction->setToolTip( i18n("Show the list of headers in Enterprise style") );
00499 raction->setExclusiveGroup( "view_headers_group" );
00500 headerMenu->insert(raction);
00501
00502 raction = new TDERadioAction( i18n("View->headers->", "&Fancy Headers"), 0,
00503 TQT_TQOBJECT(this), TQT_SLOT(slotFancyHeaders()),
00504 ac, "view_headers_fancy" );
00505 raction->setToolTip( i18n("Show the list of headers in a fancy format") );
00506 raction->setExclusiveGroup( "view_headers_group" );
00507 headerMenu->insert( raction );
00508
00509 raction = new TDERadioAction( i18n("View->headers->", "&Brief Headers"), 0,
00510 TQT_TQOBJECT(this), TQT_SLOT(slotBriefHeaders()),
00511 ac, "view_headers_brief" );
00512 raction->setToolTip( i18n("Show brief list of message headers") );
00513 raction->setExclusiveGroup( "view_headers_group" );
00514 headerMenu->insert( raction );
00515
00516 raction = new TDERadioAction( i18n("View->headers->", "&Standard Headers"), 0,
00517 TQT_TQOBJECT(this), TQT_SLOT(slotStandardHeaders()),
00518 ac, "view_headers_standard" );
00519 raction->setToolTip( i18n("Show standard list of message headers") );
00520 raction->setExclusiveGroup( "view_headers_group" );
00521 headerMenu->insert( raction );
00522
00523 raction = new TDERadioAction( i18n("View->headers->", "&Long Headers"), 0,
00524 TQT_TQOBJECT(this), TQT_SLOT(slotLongHeaders()),
00525 ac, "view_headers_long" );
00526 raction->setToolTip( i18n("Show long list of message headers") );
00527 raction->setExclusiveGroup( "view_headers_group" );
00528 headerMenu->insert( raction );
00529
00530 raction = new TDERadioAction( i18n("View->headers->", "&All Headers"), 0,
00531 TQT_TQOBJECT(this), TQT_SLOT(slotAllHeaders()),
00532 ac, "view_headers_all" );
00533 raction->setToolTip( i18n("Show all message headers") );
00534 raction->setExclusiveGroup( "view_headers_group" );
00535 headerMenu->insert( raction );
00536
00537
00538 TDEActionMenu *attachmentMenu =
00539 new TDEActionMenu( i18n("View->", "&Attachments"), ac, "view_attachments" );
00540 attachmentMenu->setToolTip( i18n("Choose display style of attachments") );
00541 connect( attachmentMenu, TQT_SIGNAL(activated()),
00542 TQT_TQOBJECT(this), TQT_SLOT(slotCycleAttachmentStrategy()) );
00543
00544 raction = new TDERadioAction( i18n("View->attachments->", "&As Icons"), 0,
00545 TQT_TQOBJECT(this), TQT_SLOT(slotIconicAttachments()),
00546 ac, "view_attachments_as_icons" );
00547 raction->setToolTip( i18n("Show all attachments as icons. Click to see them.") );
00548 raction->setExclusiveGroup( "view_attachments_group" );
00549 attachmentMenu->insert( raction );
00550
00551 raction = new TDERadioAction( i18n("View->attachments->", "&Smart"), 0,
00552 TQT_TQOBJECT(this), TQT_SLOT(slotSmartAttachments()),
00553 ac, "view_attachments_smart" );
00554 raction->setToolTip( i18n("Show attachments as suggested by sender.") );
00555 raction->setExclusiveGroup( "view_attachments_group" );
00556 attachmentMenu->insert( raction );
00557
00558 raction = new TDERadioAction( i18n("View->attachments->", "&Inline"), 0,
00559 TQT_TQOBJECT(this), TQT_SLOT(slotInlineAttachments()),
00560 ac, "view_attachments_inline" );
00561 raction->setToolTip( i18n("Show all attachments inline (if possible)") );
00562 raction->setExclusiveGroup( "view_attachments_group" );
00563 attachmentMenu->insert( raction );
00564
00565 raction = new TDERadioAction( i18n("View->attachments->", "&Hide"), 0,
00566 TQT_TQOBJECT(this), TQT_SLOT(slotHideAttachments()),
00567 ac, "view_attachments_hide" );
00568 raction->setToolTip( i18n("Do not show attachments in the message viewer") );
00569 raction->setExclusiveGroup( "view_attachments_group" );
00570 attachmentMenu->insert( raction );
00571
00572 mHeaderOnlyAttachmentsAction = new TDERadioAction( i18n( "View->attachments->", "In Header &Only" ), 0,
00573 TQT_TQOBJECT(this), TQT_SLOT( slotHeaderOnlyAttachments() ),
00574 ac, "view_attachments_headeronly" );
00575 mHeaderOnlyAttachmentsAction->setToolTip( i18n( "Show Attachments only in the header of the mail" ) );
00576 mHeaderOnlyAttachmentsAction->setExclusiveGroup( "view_attachments_group" );
00577 attachmentMenu->insert( mHeaderOnlyAttachmentsAction );
00578
00579
00580 mSelectEncodingAction = new TDESelectAction( i18n( "&Set Encoding" ), "charset", 0,
00581 TQT_TQOBJECT(this), TQT_SLOT( slotSetEncoding() ),
00582 ac, "encoding" );
00583 TQStringList encodings = KMMsgBase::supportedEncodings( false );
00584 encodings.prepend( i18n( "Auto" ) );
00585 mSelectEncodingAction->setItems( encodings );
00586 mSelectEncodingAction->setCurrentItem( 0 );
00587
00588 mMailToComposeAction = new TDEAction( i18n("New Message To..."), "mail-message-new",
00589 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoCompose()), ac,
00590 "mailto_compose" );
00591 mMailToReplyAction = new TDEAction( i18n("Reply To..."), "mail-reply-sender",
00592 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoReply()), ac,
00593 "mailto_reply" );
00594 mMailToForwardAction = new TDEAction( i18n("Forward To..."), "mail-forward",
00595 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoForward()), ac,
00596 "mailto_forward" );
00597 mAddAddrBookAction = new TDEAction( i18n("Add to Address Book"),
00598 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoAddAddrBook()),
00599 ac, "add_addr_book" );
00600 mOpenAddrBookAction = new TDEAction( i18n("Open in Address Book"),
00601 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoOpenAddrBook()),
00602 ac, "openin_addr_book" );
00603 mCopyAction = KStdAction::copy( TQT_TQOBJECT(this), TQT_SLOT(slotCopySelectedText()), ac, "kmail_copy");
00604 mSelectAllAction = new TDEAction( i18n("Select All Text"), CTRL+SHIFT+Key_A, TQT_TQOBJECT(this),
00605 TQT_SLOT(selectAll()), ac, "mark_all_text" );
00606 mCopyURLAction = new TDEAction( i18n("Copy Link Address"), 0, TQT_TQOBJECT(this),
00607 TQT_SLOT(slotUrlCopy()), ac, "copy_url" );
00608 mUrlOpenAction = new TDEAction( i18n("Open URL"), 0, TQT_TQOBJECT(this),
00609 TQT_SLOT(slotUrlOpen()), ac, "open_url" );
00610 mAddBookmarksAction = new TDEAction( i18n("Bookmark This Link"),
00611 "bookmark_add",
00612 0, TQT_TQOBJECT(this), TQT_SLOT(slotAddBookmarks()),
00613 ac, "add_bookmarks" );
00614 mUrlSaveAsAction = new TDEAction( i18n("Save Link As..."), 0, TQT_TQOBJECT(this),
00615 TQT_SLOT(slotUrlSave()), ac, "saveas_url" );
00616
00617 mToggleFixFontAction = new TDEToggleAction( i18n("Use Fi&xed Font"),
00618 Key_X, TQT_TQOBJECT(this), TQT_SLOT(slotToggleFixedFont()),
00619 ac, "toggle_fixedfont" );
00620
00621 mStartIMChatAction = new TDEAction( i18n("Chat &With..."), 0, TQT_TQOBJECT(this),
00622 TQT_SLOT(slotIMChat()), ac, "start_im_chat" );
00623 }
00624
00625
00626 TDERadioAction *KMReaderWin::actionForHeaderStyle( const HeaderStyle * style, const HeaderStrategy * strategy ) {
00627 if ( !mActionCollection )
00628 return 0;
00629 const char * actionName = 0;
00630 if ( style == HeaderStyle::enterprise() )
00631 actionName = "view_headers_enterprise";
00632 if ( style == HeaderStyle::fancy() )
00633 actionName = "view_headers_fancy";
00634 else if ( style == HeaderStyle::brief() )
00635 actionName = "view_headers_brief";
00636 else if ( style == HeaderStyle::plain() ) {
00637 if ( strategy == HeaderStrategy::standard() )
00638 actionName = "view_headers_standard";
00639 else if ( strategy == HeaderStrategy::rich() )
00640 actionName = "view_headers_long";
00641 else if ( strategy == HeaderStrategy::all() )
00642 actionName = "view_headers_all";
00643 }
00644 if ( actionName )
00645 return static_cast<TDERadioAction*>(mActionCollection->action(actionName));
00646 else
00647 return 0;
00648 }
00649
00650 TDERadioAction *KMReaderWin::actionForAttachmentStrategy( const AttachmentStrategy * as ) {
00651 if ( !mActionCollection )
00652 return 0;
00653 const char * actionName = 0;
00654 if ( as == AttachmentStrategy::iconic() )
00655 actionName = "view_attachments_as_icons";
00656 else if ( as == AttachmentStrategy::smart() )
00657 actionName = "view_attachments_smart";
00658 else if ( as == AttachmentStrategy::inlined() )
00659 actionName = "view_attachments_inline";
00660 else if ( as == AttachmentStrategy::hidden() )
00661 actionName = "view_attachments_hide";
00662 else if ( as == AttachmentStrategy::headerOnly() )
00663 actionName = "view_attachments_headeronly";
00664
00665 if ( actionName )
00666 return static_cast<TDERadioAction*>(mActionCollection->action(actionName));
00667 else
00668 return 0;
00669 }
00670
00671 void KMReaderWin::slotEnterpriseHeaders() {
00672 setHeaderStyleAndStrategy( HeaderStyle::enterprise(),
00673 HeaderStrategy::rich() );
00674 if( !mExternalWindow )
00675 writeConfig();
00676 }
00677
00678 void KMReaderWin::slotFancyHeaders() {
00679 setHeaderStyleAndStrategy( HeaderStyle::fancy(),
00680 HeaderStrategy::rich() );
00681 if( !mExternalWindow )
00682 writeConfig();
00683 }
00684
00685 void KMReaderWin::slotBriefHeaders() {
00686 setHeaderStyleAndStrategy( HeaderStyle::brief(),
00687 HeaderStrategy::brief() );
00688 if( !mExternalWindow )
00689 writeConfig();
00690 }
00691
00692 void KMReaderWin::slotStandardHeaders() {
00693 setHeaderStyleAndStrategy( HeaderStyle::plain(),
00694 HeaderStrategy::standard());
00695 writeConfig();
00696 }
00697
00698 void KMReaderWin::slotLongHeaders() {
00699 setHeaderStyleAndStrategy( HeaderStyle::plain(),
00700 HeaderStrategy::rich() );
00701 if( !mExternalWindow )
00702 writeConfig();
00703 }
00704
00705 void KMReaderWin::slotAllHeaders() {
00706 setHeaderStyleAndStrategy( HeaderStyle::plain(),
00707 HeaderStrategy::all() );
00708 if( !mExternalWindow )
00709 writeConfig();
00710 }
00711
00712 void KMReaderWin::slotLevelQuote( int l )
00713 {
00714 mLevelQuote = l;
00715 saveRelativePosition();
00716 update(true);
00717 }
00718
00719 void KMReaderWin::slotCycleHeaderStyles() {
00720 const HeaderStrategy * strategy = headerStrategy();
00721 const HeaderStyle * style = headerStyle();
00722
00723 const char * actionName = 0;
00724 if ( style == HeaderStyle::enterprise() ) {
00725 slotFancyHeaders();
00726 actionName = "view_headers_fancy";
00727 }
00728 if ( style == HeaderStyle::fancy() ) {
00729 slotBriefHeaders();
00730 actionName = "view_headers_brief";
00731 } else if ( style == HeaderStyle::brief() ) {
00732 slotStandardHeaders();
00733 actionName = "view_headers_standard";
00734 } else if ( style == HeaderStyle::plain() ) {
00735 if ( strategy == HeaderStrategy::standard() ) {
00736 slotLongHeaders();
00737 actionName = "view_headers_long";
00738 } else if ( strategy == HeaderStrategy::rich() ) {
00739 slotAllHeaders();
00740 actionName = "view_headers_all";
00741 } else if ( strategy == HeaderStrategy::all() ) {
00742 slotEnterpriseHeaders();
00743 actionName = "view_headers_enterprise";
00744 }
00745 }
00746
00747 if ( actionName )
00748 static_cast<TDERadioAction*>( mActionCollection->action( actionName ) )->setChecked( true );
00749 }
00750
00751
00752 void KMReaderWin::slotIconicAttachments() {
00753 setAttachmentStrategy( AttachmentStrategy::iconic() );
00754 }
00755
00756 void KMReaderWin::slotSmartAttachments() {
00757 setAttachmentStrategy( AttachmentStrategy::smart() );
00758 }
00759
00760 void KMReaderWin::slotInlineAttachments() {
00761 setAttachmentStrategy( AttachmentStrategy::inlined() );
00762 }
00763
00764 void KMReaderWin::slotHideAttachments() {
00765 setAttachmentStrategy( AttachmentStrategy::hidden() );
00766 }
00767
00768 void KMReaderWin::slotHeaderOnlyAttachments() {
00769 setAttachmentStrategy( AttachmentStrategy::headerOnly() );
00770 }
00771
00772 void KMReaderWin::slotCycleAttachmentStrategy() {
00773 setAttachmentStrategy( attachmentStrategy()->next() );
00774 TDERadioAction * action = actionForAttachmentStrategy( attachmentStrategy() );
00775 assert( action );
00776 action->setChecked( true );
00777 }
00778
00779
00780
00781 KMReaderWin::~KMReaderWin()
00782 {
00783 if (message()) {
00784 message()->detach( this );
00785 }
00786 clearBodyPartMementos();
00787 delete mHtmlWriter; mHtmlWriter = 0;
00788 delete mCSSHelper;
00789 if (mAutoDelete) delete message();
00790 delete mRootNode; mRootNode = 0;
00791 removeTempFiles();
00792 }
00793
00794
00795
00796 void KMReaderWin::slotMessageArrived( KMMessage *msg )
00797 {
00798 if (msg && ((KMMsgBase*)msg)->isMessage()) {
00799 if ( msg->getMsgSerNum() == mWaitingForSerNum ) {
00800 setMsg( msg, true );
00801 } else {
00802
00803 }
00804 }
00805 }
00806
00807
00808 void KMReaderWin::update( KMail::Interface::Observable * observable )
00809 {
00810 if ( !mAtmUpdate ) {
00811
00812
00813 updateReaderWin();
00814 return;
00815 }
00816
00817 if ( !mRootNode )
00818 return;
00819
00820 KMMessage* msg = static_cast<KMMessage*>( observable );
00821 assert( msg != 0 );
00822
00823
00824 if ( !msg->lastUpdatedPart() ) {
00825 kdDebug(5006) << "KMReaderWin::update - no updated part" << endl;
00826 return;
00827 }
00828 partNode* node = mRootNode->findNodeForDwPart( msg->lastUpdatedPart() );
00829 if ( !node ) {
00830 kdDebug(5006) << "KMReaderWin::update - can't find node for part" << endl;
00831 return;
00832 }
00833 node->setDwPart( msg->lastUpdatedPart() );
00834
00835
00836
00837 ::chmod( TQFile::encodeName( mAtmCurrentName ), S_IRWXU );
00838 TQByteArray data = node->msgPart().bodyDecodedBinary();
00839 size_t size = data.size();
00840 if ( node->msgPart().type() == DwMime::kTypeText && size) {
00841 size = KMail::Util::crlf2lf( data.data(), size );
00842 }
00843 KPIM::kBytesToFile( data.data(), size, mAtmCurrentName, false, false, false );
00844 ::chmod( TQFile::encodeName( mAtmCurrentName ), S_IRUSR );
00845
00846 mAtmUpdate = false;
00847 }
00848
00849
00850 void KMReaderWin::removeTempFiles()
00851 {
00852 for (TQStringList::Iterator it = mTempFiles.begin(); it != mTempFiles.end();
00853 it++)
00854 {
00855 TQFile::remove(*it);
00856 }
00857 mTempFiles.clear();
00858 for (TQStringList::Iterator it = mTempDirs.begin(); it != mTempDirs.end();
00859 it++)
00860 {
00861 TQDir(*it).rmdir(*it);
00862 }
00863 mTempDirs.clear();
00864 }
00865
00866
00867
00868 bool KMReaderWin::event(TQEvent *e)
00869 {
00870 if (e->type() == TQEvent::ApplicationPaletteChange)
00871 {
00872 delete mCSSHelper;
00873 mCSSHelper = new KMail::CSSHelper( TQPaintDeviceMetrics( mViewer->view() ) );
00874 if (message())
00875 message()->readConfig();
00876 update( true );
00877 return true;
00878 }
00879 return TQWidget::event(e);
00880 }
00881
00882
00883
00884 void KMReaderWin::readConfig(void)
00885 {
00886 const TDEConfigGroup mdnGroup( KMKernel::config(), "MDN" );
00887 TDEConfigGroup reader( KMKernel::config(), "Reader" );
00888
00889 delete mCSSHelper;
00890 mCSSHelper = new KMail::CSSHelper( TQPaintDeviceMetrics( mViewer->view() ) );
00891
00892 mNoMDNsWhenEncrypted = mdnGroup.readBoolEntry( "not-send-when-encrypted", true );
00893
00894 mUseFixedFont = reader.readBoolEntry( "useFixedFont", false );
00895 if ( mToggleFixFontAction )
00896 mToggleFixFontAction->setChecked( mUseFixedFont );
00897
00898 mHtmlMail = reader.readBoolEntry( "htmlMail", false );
00899 mHtmlLoadExternal = reader.readBoolEntry( "htmlLoadExternal", false );
00900
00901 setHeaderStyleAndStrategy( HeaderStyle::create( reader.readEntry( "header-style", "fancy" ) ),
00902 HeaderStrategy::create( reader.readEntry( "header-set-displayed", "rich" ) ) );
00903 TDERadioAction *raction = actionForHeaderStyle( headerStyle(), headerStrategy() );
00904 if ( raction )
00905 raction->setChecked( true );
00906
00907 setAttachmentStrategy( AttachmentStrategy::create( reader.readEntry( "attachment-strategy", "smart" ) ) );
00908 raction = actionForAttachmentStrategy( attachmentStrategy() );
00909 if ( raction )
00910 raction->setChecked( true );
00911
00912
00913
00914 mShowColorbar = reader.readBoolEntry( "showColorbar", Kpgp::Module::getKpgp()->usePGP() );
00915
00916
00917
00918 reader.writeEntry( "showColorbar", mShowColorbar );
00919
00920 mMimeTreeAtBottom = reader.readEntry( "MimeTreeLocation", "bottom" ) != "top";
00921 const TQString s = reader.readEntry( "MimeTreeMode", "smart" );
00922 if ( s == "never" )
00923 mMimeTreeMode = 0;
00924 else if ( s == "always" )
00925 mMimeTreeMode = 2;
00926 else
00927 mMimeTreeMode = 1;
00928
00929 const int mimeH = reader.readNumEntry( "MimePaneHeight", 100 );
00930 const int messageH = reader.readNumEntry( "MessagePaneHeight", 180 );
00931 mSplitterSizes.clear();
00932 if ( mMimeTreeAtBottom )
00933 mSplitterSizes << messageH << mimeH;
00934 else
00935 mSplitterSizes << mimeH << messageH;
00936
00937 adjustLayout();
00938
00939 readGlobalOverrideCodec();
00940
00941 if (message())
00942 update();
00943 KMMessage::readConfig();
00944 }
00945
00946
00947 void KMReaderWin::adjustLayout() {
00948 if ( mMimeTreeAtBottom )
00949 mSplitter->moveToLast( mMimePartTree );
00950 else
00951 mSplitter->moveToFirst( mMimePartTree );
00952 mSplitter->setSizes( mSplitterSizes );
00953
00954 if ( mMimeTreeMode == 2 && mMsgDisplay )
00955 mMimePartTree->show();
00956 else
00957 mMimePartTree->hide();
00958
00959 if ( mShowColorbar && mMsgDisplay )
00960 mColorBar->show();
00961 else
00962 mColorBar->hide();
00963 }
00964
00965
00966 void KMReaderWin::saveSplitterSizes( TDEConfigBase & c ) const {
00967 if ( !mSplitter || !mMimePartTree )
00968 return;
00969 if ( mMimePartTree->isHidden() )
00970 return;
00971
00972 c.writeEntry( "MimePaneHeight", mSplitter->sizes()[ mMimeTreeAtBottom ? 1 : 0 ] );
00973 c.writeEntry( "MessagePaneHeight", mSplitter->sizes()[ mMimeTreeAtBottom ? 0 : 1 ] );
00974 }
00975
00976
00977 void KMReaderWin::writeConfig( bool sync ) const {
00978 TDEConfigGroup reader( KMKernel::config(), "Reader" );
00979
00980 reader.writeEntry( "useFixedFont", mUseFixedFont );
00981 if ( headerStyle() )
00982 reader.writeEntry( "header-style", headerStyle()->name() );
00983 if ( headerStrategy() )
00984 reader.writeEntry( "header-set-displayed", headerStrategy()->name() );
00985 if ( attachmentStrategy() )
00986 reader.writeEntry( "attachment-strategy", attachmentStrategy()->name() );
00987
00988 saveSplitterSizes( reader );
00989
00990 if ( sync )
00991 kmkernel->slotRequestConfigSync();
00992 }
00993
00994
00995 void KMReaderWin::initHtmlWidget(void)
00996 {
00997 mViewer->widget()->setFocusPolicy(TQ_WheelFocus);
00998
00999 mViewer->setPluginsEnabled(false);
01000 mViewer->setJScriptEnabled(false);
01001 mViewer->setJavaEnabled(false);
01002 mViewer->setMetaRefreshEnabled(false);
01003 mViewer->setURLCursor(KCursor::handCursor());
01004
01005 mViewer->view()->setLineWidth(0);
01006
01007 mViewer->view()->viewport()->installEventFilter( this );
01008
01009 if ( !htmlWriter() )
01010 #ifdef KMAIL_READER_HTML_DEBUG
01011 mHtmlWriter = new TeeHtmlWriter( new FileHtmlWriter( TQString() ),
01012 new KHtmlPartHtmlWriter( mViewer, 0 ) );
01013 #else
01014 mHtmlWriter = new KHtmlPartHtmlWriter( mViewer, 0 );
01015 #endif
01016
01017 connect(mViewer->browserExtension(),
01018 TQT_SIGNAL(openURLRequest(const KURL &, const KParts::URLArgs &)),this,
01019 TQT_SLOT(slotUrlOpen(const KURL &)));
01020 connect(mViewer->browserExtension(),
01021 TQT_SIGNAL(createNewWindow(const KURL &, const KParts::URLArgs &)),this,
01022 TQT_SLOT(slotUrlOpen(const KURL &)));
01023 connect(mViewer,TQT_SIGNAL(popupMenu(const TQString &, const TQPoint &)),
01024 TQT_SLOT(slotUrlPopup(const TQString &, const TQPoint &)));
01025 connect( kmkernel->imProxy(), TQT_SIGNAL( sigContactPresenceChanged( const TQString & ) ),
01026 TQT_TQOBJECT(this), TQT_SLOT( contactStatusChanged( const TQString & ) ) );
01027 connect( kmkernel->imProxy(), TQT_SIGNAL( sigPresenceInfoExpired() ),
01028 TQT_TQOBJECT(this), TQT_SLOT( updateReaderWin() ) );
01029 }
01030
01031 void KMReaderWin::contactStatusChanged( const TQString &uid)
01032 {
01033
01034
01035 DOM::NodeList presenceNodes = mViewer->htmlDocument()
01036 .getElementsByName( DOM::DOMString( TQString::fromLatin1("presence-") + uid ) );
01037 for ( unsigned int i = 0; i < presenceNodes.length(); ++i ) {
01038 DOM::Node n = presenceNodes.item( i );
01039 kdDebug( 5006 ) << "name is " << n.nodeName().string() << endl;
01040 kdDebug( 5006 ) << "value of content was " << n.firstChild().nodeValue().string() << endl;
01041 TQString newPresence = kmkernel->imProxy()->presenceString( uid );
01042 if ( newPresence.isNull() )
01043 newPresence = TQString::fromLatin1( "ENOIMRUNNING" );
01044 n.firstChild().setNodeValue( newPresence );
01045
01046 }
01047
01048 }
01049
01050 void KMReaderWin::setAttachmentStrategy( const AttachmentStrategy * strategy ) {
01051 mAttachmentStrategy = strategy ? strategy : AttachmentStrategy::smart();
01052 update( true );
01053 }
01054
01055 void KMReaderWin::setHeaderStyleAndStrategy( const HeaderStyle * style,
01056 const HeaderStrategy * strategy ) {
01057 mHeaderStyle = style ? style : HeaderStyle::fancy();
01058 mHeaderStrategy = strategy ? strategy : HeaderStrategy::rich();
01059 if ( mHeaderOnlyAttachmentsAction ) {
01060 const bool styleHasAttachmentQuickList = mHeaderStyle == HeaderStyle::fancy() ||
01061 mHeaderStyle == HeaderStyle::enterprise();
01062 mHeaderOnlyAttachmentsAction->setEnabled( styleHasAttachmentQuickList );
01063 if ( !styleHasAttachmentQuickList && mAttachmentStrategy == AttachmentStrategy::headerOnly() ) {
01064
01065
01066 setAttachmentStrategy( AttachmentStrategy::smart() );
01067 }
01068 }
01069 update( true );
01070 }
01071
01072
01073 void KMReaderWin::setOverrideEncoding( const TQString & encoding )
01074 {
01075 if ( encoding == mOverrideEncoding )
01076 return;
01077
01078 mOverrideEncoding = encoding;
01079 if ( mSelectEncodingAction ) {
01080 if ( encoding.isEmpty() ) {
01081 mSelectEncodingAction->setCurrentItem( 0 );
01082 }
01083 else {
01084 TQStringList encodings = mSelectEncodingAction->items();
01085 uint i = 0;
01086 for ( TQStringList::const_iterator it = encodings.begin(), end = encodings.end(); it != end; ++it, ++i ) {
01087 if ( TDEGlobal::charsets()->encodingForName( *it ) == encoding ) {
01088 mSelectEncodingAction->setCurrentItem( i );
01089 break;
01090 }
01091 }
01092 if ( i == encodings.size() ) {
01093
01094 kdWarning(5006) << "Unknown override character encoding \"" << encoding
01095 << "\". Using Auto instead." << endl;
01096 mSelectEncodingAction->setCurrentItem( 0 );
01097 mOverrideEncoding = TQString();
01098 }
01099 }
01100 }
01101 update( true );
01102 }
01103
01104
01105 void KMReaderWin::setPrintFont( const TQFont& font )
01106 {
01107
01108 mCSSHelper->setPrintFont( font );
01109 }
01110
01111
01112 const TQTextCodec * KMReaderWin::overrideCodec() const
01113 {
01114 if ( mOverrideEncoding.isEmpty() || mOverrideEncoding == "Auto" )
01115 return 0;
01116 else
01117 return KMMsgBase::codecForName( mOverrideEncoding.latin1() );
01118 }
01119
01120
01121 void KMReaderWin::slotSetEncoding()
01122 {
01123 if ( mSelectEncodingAction->currentItem() == 0 )
01124 mOverrideEncoding = TQString();
01125 else
01126 mOverrideEncoding = TDEGlobal::charsets()->encodingForName( mSelectEncodingAction->currentText() );
01127 update( true );
01128 }
01129
01130
01131 void KMReaderWin::readGlobalOverrideCodec()
01132 {
01133
01134 if ( GlobalSettings::self()->overrideCharacterEncoding() == mOldGlobalOverrideEncoding )
01135 return;
01136
01137 setOverrideEncoding( GlobalSettings::self()->overrideCharacterEncoding() );
01138 mOldGlobalOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding();
01139 }
01140
01141
01142 void KMReaderWin::setOriginalMsg( unsigned long serNumOfOriginalMessage, int nodeIdOffset )
01143 {
01144 mSerNumOfOriginalMessage = serNumOfOriginalMessage;
01145 mNodeIdOffset = nodeIdOffset;
01146 }
01147
01148
01149 void KMReaderWin::setMsg( KMMessage* aMsg, bool force, bool updateOnly )
01150 {
01151 if ( aMsg ) {
01152 kdDebug(5006) << "(" << aMsg->getMsgSerNum() << ", last " << mLastSerNum << ") " << aMsg->subject() << " "
01153 << aMsg->fromStrip() << ", readyToShow " << (aMsg->readyToShow()) << endl;
01154 }
01155
01156
01157 if ( aMsg && aMsg->getMsgSerNum() != mLastSerNum && !updateOnly ){
01158 mLevelQuote = GlobalSettings::self()->collapseQuoteLevelSpin()-1;
01159 mShowRawToltecMail = !GlobalSettings::self()->showToltecReplacementText();
01160 clearBodyPartMementos();
01161 }
01162 if ( mPrinting )
01163 mLevelQuote = -1;
01164
01165 bool complete = true;
01166 if ( aMsg &&
01167 !aMsg->readyToShow() &&
01168 (aMsg->getMsgSerNum() != mLastSerNum) &&
01169 !aMsg->isComplete() )
01170 complete = false;
01171
01172
01173 if (!force && aMsg && mLastSerNum != 0 && aMsg->getMsgSerNum() == mLastSerNum)
01174 return;
01175
01176
01177 if (aMsg && message())
01178 message()->detach( this );
01179 if (aMsg)
01180 aMsg->attach( this );
01181 mAtmUpdate = false;
01182
01183 mDelayedMarkTimer.stop();
01184
01185 mMessage = 0;
01186 if ( !aMsg ) {
01187 mWaitingForSerNum = 0;
01188 mLastSerNum = 0;
01189 } else {
01190 mLastSerNum = aMsg->getMsgSerNum();
01191
01192
01193
01194
01195
01196 if (message() != aMsg) {
01197 mMessage = aMsg;
01198 mLastSerNum = 0;
01199 }
01200 }
01201
01202 if (aMsg) {
01203 aMsg->setOverrideCodec( overrideCodec() );
01204 aMsg->setDecodeHTML( htmlMail() );
01205
01206 if ( !aMsg->isComplete() )
01207 mViewer->setDNDEnabled( false );
01208 else
01209 mViewer->setDNDEnabled( true );
01210 }
01211
01212
01213
01214 if ( complete )
01215 {
01216
01217 if (force) {
01218
01219 mUpdateReaderWinTimer.stop();
01220 updateReaderWin();
01221 }
01222 else if (mUpdateReaderWinTimer.isActive())
01223 mUpdateReaderWinTimer.changeInterval( delay );
01224 else
01225 mUpdateReaderWinTimer.start( 0, true );
01226 }
01227
01228 if ( aMsg && (aMsg->isUnread() || aMsg->isNew()) && GlobalSettings::self()->delayedMarkAsRead() ) {
01229 if ( GlobalSettings::self()->delayedMarkTime() != 0 )
01230 mDelayedMarkTimer.start( GlobalSettings::self()->delayedMarkTime() * 1000, true );
01231 else
01232 slotTouchMessage();
01233 }
01234
01235 mHeaderRefreshTimer.start( 1000, false );
01236 }
01237
01238
01239 void KMReaderWin::clearCache()
01240 {
01241 mUpdateReaderWinTimer.stop();
01242 clear();
01243 mDelayedMarkTimer.stop();
01244 mLastSerNum = 0;
01245 mWaitingForSerNum = 0;
01246 mMessage = 0;
01247 }
01248
01249
01250 static const char * const kmailChanges[] = {
01251 ""
01252 };
01253 static const int numKMailChanges =
01254 sizeof kmailChanges / sizeof *kmailChanges;
01255
01256
01257
01258
01259
01260 static const char * const kmailNewFeatures[] = {
01261 I18N_NOOP("Full namespace support for IMAP"),
01262 I18N_NOOP("Offline mode"),
01263 I18N_NOOP("Sieve script management and editing"),
01264 I18N_NOOP("Account specific filtering"),
01265 I18N_NOOP("Filtering of incoming mail for online IMAP accounts"),
01266 I18N_NOOP("Online IMAP folders can be used when filtering into folders"),
01267 I18N_NOOP("Automatically delete older mails on POP servers")
01268 };
01269 static const int numKMailNewFeatures =
01270 sizeof kmailNewFeatures / sizeof *kmailNewFeatures;
01271
01272
01273
01274
01275 TQString KMReaderWin::newFeaturesMD5()
01276 {
01277 TQCString str;
01278 for ( int i = 0 ; i < numKMailChanges ; ++i )
01279 str += kmailChanges[i];
01280 for ( int i = 0 ; i < numKMailNewFeatures ; ++i )
01281 str += kmailNewFeatures[i];
01282 KMD5 md5( str );
01283 return md5.base64Digest();
01284 }
01285
01286
01287 void KMReaderWin::displaySplashPage( const TQString &info )
01288 {
01289 mMsgDisplay = false;
01290 adjustLayout();
01291
01292 TQString location = locate("data", "kmail/about/main.html");
01293 TQString content = KPIM::kFileToString(location);
01294 content = content.arg( locate( "data", "libtdepim/about/kde_infopage.css" ) );
01295 if ( kapp->reverseLayout() )
01296 content = content.arg( "@import \"%1\";" ).arg( locate( "data", "libtdepim/about/kde_infopage_rtl.css" ) );
01297 else
01298 content = content.arg( "" );
01299
01300 mViewer->begin(KURL( location ));
01301
01302 TQString fontSize = TQString::number( pointsToPixel( mCSSHelper->bodyFont().pointSize() ) );
01303 TQString appTitle = i18n("KMail");
01304 TQString catchPhrase = "";
01305 TQString quickDescription = i18n("The email client for the Trinity Desktop Environment.");
01306 mViewer->write(content.arg(fontSize).arg(appTitle).arg(catchPhrase).arg(quickDescription).arg(info));
01307 mViewer->end();
01308 }
01309
01310 void KMReaderWin::displayBusyPage()
01311 {
01312 TQString info =
01313 i18n( "<h2 style='margin-top: 0px;'>Retrieving Folder Contents</h2><p>Please wait . . .</p> " );
01314
01315 displaySplashPage( info );
01316 }
01317
01318 void KMReaderWin::displayOfflinePage()
01319 {
01320 TQString info =
01321 i18n( "<h2 style='margin-top: 0px;'>Offline</h2><p>KMail is currently in offline mode. "
01322 "Click <a href=\"kmail:goOnline\">here</a> to go online . . .</p> " );
01323
01324 displaySplashPage( info );
01325 }
01326
01327
01328
01329 void KMReaderWin::displayAboutPage()
01330 {
01331 TQString info =
01332 i18n("%1: KMail version; %2: help:// URL; %3: homepage URL; "
01333 "%4: prior KMail version; %5: prior TDE version; "
01334 "%6: generated list of new features; "
01335 "%7: First-time user text (only shown on first start); "
01336 "%8: generated list of important changes; "
01337 "--- end of comment ---",
01338 "<h2 style='margin-top: 0px;'>Welcome to KMail %1</h2><p>KMail is the email client for the Trinity "
01339 "Desktop Environment. It is designed to be fully compatible with "
01340 "Internet mailing standards including MIME, SMTP, POP3 and IMAP."
01341 "</p>\n"
01342 "<ul><li>KMail has many powerful features which are described in the "
01343 "<a href=\"%2\">documentation</a></li>\n"
01344 "<li>The <a href=\"%3\">KMail (TDE) homepage</A> offers information about "
01345 "new versions of KMail</li></ul>\n"
01346 "%8\n"
01347 "<p>Some of the new features in this release of KMail include "
01348 "(compared to KMail %4, which is part of TDE %5):</p>\n"
01349 "<ul>\n%6</ul>\n"
01350 "%7\n"
01351 "<p>We hope that you will enjoy KMail.</p>\n"
01352 "<p>Thank you,</p>\n"
01353 "<p style='margin-bottom: 0px'> The KMail Team</p>")
01354 .arg(KMAIL_VERSION)
01355 .arg("help:/kmail/index.html")
01356 .arg("http://www.trinitydesktop.org")
01357 .arg("1.8").arg("3.4");
01358
01359 TQString featureItems;
01360 for ( int i = 0 ; i < numKMailNewFeatures ; i++ )
01361 featureItems += i18n("<li>%1</li>\n").arg( i18n( kmailNewFeatures[i] ) );
01362
01363 info = info.arg( featureItems );
01364
01365 if( kmkernel->firstStart() ) {
01366 info = info.arg( i18n("<p>Please take a moment to fill in the KMail "
01367 "configuration panel at Settings->Configure "
01368 "KMail.\n"
01369 "You need to create at least a default identity and "
01370 "an incoming as well as outgoing mail account."
01371 "</p>\n") );
01372 } else {
01373 info = info.arg( TQString() );
01374 }
01375
01376 if ( ( numKMailChanges > 1 ) || ( numKMailChanges == 1 && strlen(kmailChanges[0]) > 0 ) ) {
01377 TQString changesText =
01378 i18n("<p><span style='font-size:125%; font-weight:bold;'>"
01379 "Important changes</span> (compared to KMail %1):</p>\n")
01380 .arg("1.8");
01381 changesText += "<ul>\n";
01382 for ( int i = 0 ; i < numKMailChanges ; i++ )
01383 changesText += i18n("<li>%1</li>\n").arg( i18n( kmailChanges[i] ) );
01384 changesText += "</ul>\n";
01385 info = info.arg( changesText );
01386 }
01387 else
01388 info = info.arg("");
01389
01390 displaySplashPage( info );
01391 }
01392
01393 void KMReaderWin::enableMsgDisplay() {
01394 mMsgDisplay = true;
01395 adjustLayout();
01396 }
01397
01398
01399
01400
01401 void KMReaderWin::updateReaderWin()
01402 {
01403 if (!mMsgDisplay) return;
01404
01405 mViewer->setOnlyLocalReferences(!htmlLoadExternal());
01406
01407 htmlWriter()->reset();
01408
01409 KMFolder* folder = 0;
01410 if (message(&folder))
01411 {
01412 if ( mShowColorbar )
01413 mColorBar->show();
01414 else
01415 mColorBar->hide();
01416 displayMessage();
01417 }
01418 else
01419 {
01420 mColorBar->hide();
01421 mMimePartTree->hide();
01422 mMimePartTree->clear();
01423 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
01424 htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) + "</body></html>" );
01425 htmlWriter()->end();
01426 }
01427
01428 if (mSavedRelativePosition)
01429 {
01430 TQScrollView * scrollview = static_cast<TQScrollView *>(mViewer->widget());
01431 scrollview->setContentsPos( 0,
01432 tqRound( scrollview->contentsHeight() * mSavedRelativePosition ) );
01433 mSavedRelativePosition = 0;
01434 }
01435 }
01436
01437
01438 int KMReaderWin::pointsToPixel(int pointSize) const
01439 {
01440 const TQPaintDeviceMetrics pdm(mViewer->view());
01441
01442 return (pointSize * pdm.logicalDpiY() + 36) / 72;
01443 }
01444
01445
01446 void KMReaderWin::showHideMimeTree( bool isPlainTextTopLevel ) {
01447 if ( mMimeTreeMode == 2 ||
01448 ( mMimeTreeMode == 1 && !isPlainTextTopLevel ) )
01449 mMimePartTree->show();
01450 else {
01451
01452 TDEConfigGroup reader( KMKernel::config(), "Reader" );
01453 saveSplitterSizes( reader );
01454 mMimePartTree->hide();
01455 }
01456 }
01457
01458 void KMReaderWin::displayMessage() {
01459 KMMessage * msg = message();
01460
01461 mMimePartTree->clear();
01462 showHideMimeTree( !msg ||
01463 ( msg->type() == DwMime::kTypeText
01464 && msg->subtype() == DwMime::kSubtypePlain ) );
01465
01466 if ( !msg )
01467 return;
01468
01469 msg->setOverrideCodec( overrideCodec() );
01470
01471 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
01472 htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
01473
01474 if (!parent())
01475 setCaption(msg->subject());
01476
01477 removeTempFiles();
01478
01479 mColorBar->setNeutralMode();
01480
01481 parseMsg(msg);
01482
01483 if( mColorBar->isNeutral() )
01484 mColorBar->setNormalMode();
01485
01486 htmlWriter()->queue("</body></html>");
01487 htmlWriter()->flush();
01488
01489 TQTimer::singleShot( 1, TQT_TQOBJECT(this), TQT_SLOT(injectAttachments()) );
01490 }
01491
01492 static bool message_was_saved_decrypted_before( const KMMessage * msg ) {
01493 if ( !msg )
01494 return false;
01495
01496 return msg->msgId().stripWhiteSpace().startsWith( "<DecryptedMsg." );
01497 }
01498
01499
01500 void KMReaderWin::parseMsg(KMMessage* aMsg)
01501 {
01502 KMMessagePart msgPart;
01503 TQCString subtype, contDisp;
01504 TQByteArray str;
01505
01506 assert(aMsg!=0);
01507
01508 aMsg->setIsBeingParsed( true );
01509
01510 if ( mRootNode && !mRootNode->processed() )
01511 {
01512 kdWarning() << "The root node is not yet processed! Danger!\n";
01513 return;
01514 } else
01515 delete mRootNode;
01516 mRootNode = partNode::fromMessage( aMsg, this );
01517 const TQCString mainCntTypeStr = mRootNode->typeString() + '/' + mRootNode->subTypeString();
01518
01519 TQString cntDesc = aMsg->subject();
01520 if( cntDesc.isEmpty() )
01521 cntDesc = i18n("( body part )");
01522 TDEIO::filesize_t cntSize = aMsg->msgSize();
01523 TQString cntEnc;
01524 if( aMsg->contentTransferEncodingStr().isEmpty() )
01525 cntEnc = "7bit";
01526 else
01527 cntEnc = aMsg->contentTransferEncodingStr();
01528
01529
01530 mRootNode->fillMimePartTree( 0,
01531 mMimePartTree,
01532 cntDesc,
01533 mainCntTypeStr,
01534 cntEnc,
01535 cntSize );
01536
01537 partNode* vCardNode = mRootNode->findType( DwMime::kTypeText, DwMime::kSubtypeXVCard );
01538 bool hasVCard = false;
01539 if( vCardNode ) {
01540
01541
01542 TDEABC::VCardConverter t;
01543 #if defined(KABC_VCARD_ENCODING_FIX)
01544 const TQByteArray vcard = vCardNode->msgPart().bodyDecodedBinary();
01545 if ( !t.parseVCardsRaw( vcard.data() ).empty() ) {
01546 #else
01547 const TQString vcard = vCardNode->msgPart().bodyToUnicode( overrideCodec() );
01548 if ( !t.parseVCards( vcard ).empty() ) {
01549 #endif
01550 hasVCard = true;
01551 writeMessagePartToTempFile( &vCardNode->msgPart(), vCardNode->nodeId() );
01552 }
01553 }
01554
01555 if ( !mRootNode || !mRootNode->isToltecMessage() || mShowRawToltecMail ) {
01556 htmlWriter()->queue( writeMsgHeader(aMsg, hasVCard ? vCardNode : 0, true ) );
01557 }
01558
01559
01560 ObjectTreeParser otp( this );
01561 otp.setAllowAsync( true );
01562 otp.setShowRawToltecMail( mShowRawToltecMail );
01563 otp.parseObjectTree( mRootNode );
01564
01565
01566
01567 KMMsgEncryptionState encryptionState = mRootNode->overallEncryptionState();
01568 KMMsgSignatureState signatureState = mRootNode->overallSignatureState();
01569
01570 if (aMsg != message()) {
01571 displayMessage();
01572 return;
01573 }
01574 aMsg->setEncryptionState( encryptionState );
01575
01576
01577 if ( signatureState != KMMsgNotSigned ||
01578 aMsg->signatureState() == KMMsgSignatureStateUnknown ) {
01579 aMsg->setSignatureState( signatureState );
01580 }
01581
01582 bool emitReplaceMsgByUnencryptedVersion = false;
01583 const TDEConfigGroup reader( KMKernel::config(), "Reader" );
01584 if ( reader.readBoolEntry( "store-displayed-messages-unencrypted", false ) ) {
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599 kdDebug(5006) << "\n\n\nKMReaderWin::parseMsg() - special post-encryption handling:\n1." << endl;
01600 kdDebug(5006) << "(aMsg == msg) = " << (aMsg == message()) << endl;
01601 kdDebug(5006) << "aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() = " << (aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder()) << endl;
01602 kdDebug(5006) << "message_was_saved_decrypted_before( aMsg ) = " << message_was_saved_decrypted_before( aMsg ) << endl;
01603 kdDebug(5006) << "this->decryptMessage() = " << decryptMessage() << endl;
01604 kdDebug(5006) << "otp.hasPendingAsyncJobs() = " << otp.hasPendingAsyncJobs() << endl;
01605 kdDebug(5006) << " (KMMsgFullyEncrypted == encryptionState) = " << (KMMsgFullyEncrypted == encryptionState) << endl;
01606 kdDebug(5006) << "|| (KMMsgPartiallyEncrypted == encryptionState) = " << (KMMsgPartiallyEncrypted == encryptionState) << endl;
01607
01608
01609 if( (aMsg == message())
01610
01611 && ( aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() )
01612
01613 && !message_was_saved_decrypted_before( aMsg )
01614
01615 && decryptMessage()
01616
01617 && !otp.hasPendingAsyncJobs()
01618
01619 && ( (KMMsgFullyEncrypted == encryptionState)
01620 || (KMMsgPartiallyEncrypted == encryptionState) ) ) {
01621
01622 kdDebug(5006) << "KMReaderWin - calling objectTreeToDecryptedMsg()" << endl;
01623
01624 NewByteArray decryptedData;
01625
01626 objectTreeToDecryptedMsg( mRootNode, decryptedData, *aMsg );
01627
01628 decryptedData.appendNULL();
01629 TQCString resultString( decryptedData.data() );
01630 kdDebug(5006) << "KMReaderWin - resulting data:" << resultString << endl;
01631
01632 if( !resultString.isEmpty() ) {
01633 kdDebug(5006) << "KMReaderWin - composing unencrypted message" << endl;
01634
01635 aMsg->setBody( resultString );
01636 KMMessage* unencryptedMessage = new KMMessage( *aMsg );
01637 unencryptedMessage->setParent( 0 );
01638
01639
01640
01641
01642
01643
01644
01645
01646 kdDebug(5006) << "KMReaderWin - attach unencrypted message to aMsg" << endl;
01647 aMsg->setUnencryptedMsg( unencryptedMessage );
01648 emitReplaceMsgByUnencryptedVersion = true;
01649 }
01650 }
01651 }
01652
01653
01654 const int rootNodeCntType = mRootNode ? mRootNode->type() : DwMime::kTypeText;
01655 const int rootNodeCntSubtype = mRootNode ? mRootNode->subType() : DwMime::kSubtypePlain;
01656
01657
01658 setIdOfLastViewedMessage( aMsg->msgId() );
01659
01660 if( emitReplaceMsgByUnencryptedVersion ) {
01661 kdDebug(5006) << "KMReaderWin - invoce saving in decrypted form:" << endl;
01662 emit replaceMsgByUnencryptedVersion();
01663 } else {
01664 kdDebug(5006) << "KMReaderWin - finished parsing and displaying of message." << endl;
01665 showHideMimeTree( rootNodeCntType == DwMime::kTypeText &&
01666 rootNodeCntSubtype == DwMime::kSubtypePlain );
01667 }
01668
01669 aMsg->setIsBeingParsed( false );
01670 }
01671
01672
01673
01674 void KMReaderWin::updateHeader()
01675 {
01676
01677
01678
01679
01680
01681
01682
01683
01684 KMMessage* currentMessage = message();
01685
01686 if (currentMessage &&
01687 mHeaderStyle == HeaderStyle::fancy() &&
01688 currentMessage->parent())
01689 {
01690 int i;
01691 int divNumber = -1;
01692 DOM::NodeList divs(mViewer->document().documentElement().getElementsByTagName("div"));
01693 DOM::NodeList headerDivs(static_cast<DOM::HTMLDivElement>(divs.item(0)).getElementsByTagName("div"));
01694 for (i=0; i<((int)headerDivs.length()); i++) {
01695 if (static_cast<DOM::HTMLDivElement>(headerDivs.item(i)).id().string() == "sendersCurrentTime") {
01696 divNumber = i;
01697 break;
01698 }
01699 }
01700
01701 if (divNumber >= 0) {
01702 DOM::HTMLDivElement elem = static_cast<DOM::HTMLDivElement>(headerDivs.item(i));
01703
01704
01705
01706 TQString latestHeader = headerStyle()->format( currentMessage, headerStrategy(), "", mPrinting, false );
01707 int startPos = latestHeader.find("<div id=\"sendersCurrentTime\" style=\"");
01708 if (startPos >= 0) {
01709 latestHeader = latestHeader.mid(startPos);
01710 int endPos = latestHeader.find("</div>");
01711 if (endPos >= 0) {
01712 endPos = endPos + 6;
01713 latestHeader.truncate(endPos);
01714
01715 TQString divText = latestHeader;
01716 TQString divStyle = latestHeader;
01717
01718 divText = divText.mid(divText.find(">")+1);
01719 divText.truncate(divText.find("</div>"));
01720
01721 divStyle = divStyle.mid(TQString("<div id=\"sendersCurrentTime\" style=\"").length());
01722 divStyle.truncate(divStyle.find("\""));
01723
01724 elem.setInnerHTML(divText);
01725 elem.setAttribute("style", divStyle);
01726 elem.applyChanges();
01727 }
01728 }
01729 }
01730 }
01731 }
01732
01733
01734 TQString KMReaderWin::writeMsgHeader( KMMessage* aMsg, partNode *vCardNode, bool topLevel )
01735 {
01736 kdFatal( !headerStyle(), 5006 )
01737 << "trying to writeMsgHeader() without a header style set!" << endl;
01738 kdFatal( !headerStrategy(), 5006 )
01739 << "trying to writeMsgHeader() without a header strategy set!" << endl;
01740 TQString href;
01741 if ( vCardNode )
01742 href = vCardNode->asHREF( "body" );
01743
01744 return headerStyle()->format( aMsg, headerStrategy(), href, mPrinting, topLevel );
01745 }
01746
01747
01748
01749
01750 TQString KMReaderWin::writeMessagePartToTempFile( KMMessagePart* aMsgPart,
01751 int aPartNum )
01752 {
01753 TQString fileName = aMsgPart->fileName();
01754 if( fileName.isEmpty() )
01755 fileName = aMsgPart->name();
01756
01757
01758 TQString fname = createTempDir( TQString::number( aPartNum ) );
01759 if ( fname.isEmpty() )
01760 return TQString();
01761
01762
01763 int slashPos = fileName.findRev( '/' );
01764 if( -1 != slashPos )
01765 fileName = fileName.mid( slashPos + 1 );
01766 if( fileName.isEmpty() )
01767 fileName = "unnamed";
01768 fname += "/" + fileName;
01769
01770 TQByteArray data = aMsgPart->bodyDecodedBinary();
01771 size_t size = data.size();
01772 if ( aMsgPart->type() == DwMime::kTypeText && size) {
01773
01774 size = KMail::Util::crlf2lf( data.data(), size );
01775 }
01776 if( !KPIM::kBytesToFile( data.data(), size, fname, false, false, false ) )
01777 return TQString();
01778
01779 mTempFiles.append( fname );
01780
01781
01782 ::chmod( TQFile::encodeName( fname ), S_IRUSR );
01783
01784 return fname;
01785 }
01786
01787 TQString KMReaderWin::createTempDir( const TQString ¶m )
01788 {
01789 KTempFile *tempFile = new KTempFile( TQString(), "." + param );
01790 tempFile->setAutoDelete( true );
01791 TQString fname = tempFile->name();
01792 delete tempFile;
01793
01794 if( ::access( TQFile::encodeName( fname ), W_OK ) != 0 )
01795
01796 if( ::mkdir( TQFile::encodeName( fname ), 0 ) != 0
01797 || ::chmod( TQFile::encodeName( fname ), S_IRWXU ) != 0 )
01798 return TQString();
01799
01800 assert( !fname.isNull() );
01801
01802 mTempDirs.append( fname );
01803 return fname;
01804 }
01805
01806
01807 void KMReaderWin::showVCard( KMMessagePart *msgPart )
01808 {
01809 #if defined(KABC_VCARD_ENCODING_FIX)
01810 const TQByteArray vCard = msgPart->bodyDecodedBinary();
01811 #else
01812 const TQString vCard = msgPart->bodyToUnicode( overrideCodec() );
01813 #endif
01814 VCardViewer *vcv = new VCardViewer( this, vCard, "vCardDialog" );
01815 vcv->show();
01816 }
01817
01818
01819 void KMReaderWin::printMsg()
01820 {
01821 if (!message()) return;
01822 mViewer->view()->print();
01823 }
01824
01825
01826
01827 int KMReaderWin::msgPartFromUrl(const KURL &aUrl)
01828 {
01829 if (aUrl.isEmpty()) return -1;
01830 if (!aUrl.isLocalFile()) return -1;
01831
01832 TQString path = aUrl.path();
01833 uint right = path.findRev('/');
01834 uint left = path.findRev('.', right);
01835
01836 bool ok;
01837 int res = path.mid(left + 1, right - left - 1).toInt(&ok);
01838 return (ok) ? res : -1;
01839 }
01840
01841
01842
01843 void KMReaderWin::resizeEvent(TQResizeEvent *)
01844 {
01845 if( !mResizeTimer.isActive() )
01846 {
01847
01848
01849
01850
01851 mResizeTimer.start( 100, true );
01852 }
01853 }
01854
01855
01856
01857 void KMReaderWin::slotDelayedResize()
01858 {
01859 mSplitter->setGeometry(0, 0, width(), height());
01860 }
01861
01862
01863
01864 void KMReaderWin::slotTouchMessage()
01865 {
01866 if ( !message() )
01867 return;
01868
01869 if ( !message()->isNew() && !message()->isUnread() )
01870 return;
01871
01872 SerNumList serNums;
01873 serNums.append( message()->getMsgSerNum() );
01874 KMCommand *command = new KMSeStatusCommand( KMMsgStatusRead, serNums );
01875 command->start();
01876
01877
01878 if ( mNoMDNsWhenEncrypted &&
01879 message()->encryptionState() != KMMsgNotEncrypted &&
01880 message()->encryptionState() != KMMsgEncryptionStateUnknown )
01881 return;
01882
01883 KMFolder *folder = message()->parent();
01884 if (folder &&
01885 (folder->isOutbox() || folder->isSent() || folder->isTrash() ||
01886 folder->isDrafts() || folder->isTemplates() ) )
01887 return;
01888
01889 if ( KMMessage * receipt = message()->createMDN( MDN::ManualAction,
01890 MDN::Displayed,
01891 true ) )
01892 if ( !kmkernel->msgSender()->send( receipt ) )
01893 KMessageBox::error( this, i18n("Could not send MDN.") );
01894 }
01895
01896
01897
01898 void KMReaderWin::closeEvent(TQCloseEvent *e)
01899 {
01900 TQWidget::closeEvent(e);
01901 writeConfig();
01902 }
01903
01904
01905 bool foundSMIMEData( const TQString aUrl,
01906 TQString& displayName,
01907 TQString& libName,
01908 TQString& keyId )
01909 {
01910 static TQString showCertMan("showCertificate#");
01911 displayName = "";
01912 libName = "";
01913 keyId = "";
01914 int i1 = aUrl.find( showCertMan );
01915 if( -1 < i1 ) {
01916 i1 += showCertMan.length();
01917 int i2 = aUrl.find(" ### ", i1);
01918 if( i1 < i2 )
01919 {
01920 displayName = aUrl.mid( i1, i2-i1 );
01921 i1 = i2+5;
01922 i2 = aUrl.find(" ### ", i1);
01923 if( i1 < i2 )
01924 {
01925 libName = aUrl.mid( i1, i2-i1 );
01926 i2 += 5;
01927
01928 keyId = aUrl.mid( i2 );
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941 }
01942 }
01943 }
01944 return !keyId.isEmpty();
01945 }
01946
01947
01948
01949 void KMReaderWin::slotUrlOn(const TQString &aUrl)
01950 {
01951 const KURL url(aUrl);
01952
01953 if ( url.protocol() == "kmail" || url.protocol() == "x-kmail" || url.protocol() == "attachment"
01954 || (url.protocol().isEmpty() && url.path().isEmpty()) ) {
01955 mViewer->setDNDEnabled( false );
01956 } else {
01957 mViewer->setDNDEnabled( true );
01958 }
01959
01960 if ( aUrl.stripWhiteSpace().isEmpty() ) {
01961 KPIM::BroadcastStatus::instance()->reset();
01962 mHoveredUrl = KURL();
01963 mLastClickImagePath = TQString();
01964 return;
01965 }
01966
01967 mHoveredUrl = url;
01968
01969 const TQString msg = URLHandlerManager::instance()->statusBarMessage( url, this );
01970
01971 kdWarning( msg.isEmpty(), 5006 ) << "KMReaderWin::slotUrlOn(): Unhandled URL hover!" << endl;
01972 KPIM::BroadcastStatus::instance()->setTransienStatusMsg( msg );
01973 }
01974
01975
01976
01977 void KMReaderWin::slotUrlOpen(const KURL &aUrl, const KParts::URLArgs &)
01978 {
01979 mClickedUrl = aUrl;
01980
01981 if ( URLHandlerManager::instance()->handleClick( aUrl, this ) )
01982 return;
01983
01984 kdWarning( 5006 ) << "KMReaderWin::slotOpenUrl(): Unhandled URL click!" << endl;
01985 emit urlClicked( aUrl, Qt::LeftButton );
01986 }
01987
01988
01989 void KMReaderWin::slotUrlPopup(const TQString &aUrl, const TQPoint& aPos)
01990 {
01991 const KURL url( aUrl );
01992 mClickedUrl = url;
01993
01994 if ( url.protocol() == "mailto" ) {
01995 mCopyURLAction->setText( i18n( "Copy Email Address" ) );
01996 } else {
01997 mCopyURLAction->setText( i18n( "Copy Link Address" ) );
01998 }
01999
02000 if ( URLHandlerManager::instance()->handleContextMenuRequest( url, aPos, this ) )
02001 return;
02002
02003 if ( message() ) {
02004 kdWarning( 5006 ) << "KMReaderWin::slotUrlPopup(): Unhandled URL right-click!" << endl;
02005 emitPopupMenu( url, aPos );
02006 }
02007 }
02008
02009
02010
02011 static bool hasParentDivWithId( const DOM::Node &start, const TQString &id )
02012 {
02013 if ( start.isNull() )
02014 return false;
02015
02016 if ( start.nodeName().string() == "div" ) {
02017 for ( unsigned int i = 0; i < start.attributes().length(); i++ ) {
02018 if ( start.attributes().item( i ).nodeName().string() == "id" &&
02019 start.attributes().item( i ).nodeValue().string() == id )
02020 return true;
02021 }
02022 }
02023
02024 if ( !start.parentNode().isNull() )
02025 return hasParentDivWithId( start.parentNode(), id );
02026 else return false;
02027 }
02028
02029
02030 void KMReaderWin::showAttachmentPopup( int id, const TQString & name, const TQPoint & p )
02031 {
02032 mAtmCurrent = id;
02033 mAtmCurrentName = name;
02034 TDEPopupMenu *menu = new TDEPopupMenu();
02035 menu->insertItem(SmallIcon("document-open"),i18n("to open", "Open"), 1);
02036 menu->insertItem(i18n("Open With..."), 2);
02037 menu->insertItem(i18n("to view something", "View"), 3);
02038 menu->insertItem(SmallIcon("document-save-as"),i18n("Save As..."), 4);
02039 menu->insertItem(SmallIcon("edit-copy"), i18n("Copy"), 9 );
02040 const bool canChange = message()->parent() ? !message()->parent()->isReadOnly() : false;
02041 if ( GlobalSettings::self()->allowAttachmentEditing() && canChange )
02042 menu->insertItem(SmallIcon("edit"), i18n("Edit Attachment"), 8 );
02043 if ( GlobalSettings::self()->allowAttachmentDeletion() && canChange )
02044 menu->insertItem(SmallIcon("edit-delete"), i18n("Delete Attachment"), 7 );
02045 if ( name.endsWith( ".xia", false ) &&
02046 Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) )
02047 menu->insertItem( i18n( "Decrypt With Chiasmus..." ), 6 );
02048 menu->insertItem(i18n("Properties"), 5);
02049
02050 const bool attachmentInHeader = hasParentDivWithId( mViewer->nodeUnderMouse(), "attachmentInjectionPoint" );
02051 const bool hasScrollbar = mViewer->view()->verticalScrollBar()->isVisible();
02052 if ( attachmentInHeader && hasScrollbar ) {
02053 menu->insertItem( i18n("Scroll To"), 10 );
02054 }
02055
02056 connect(menu, TQT_SIGNAL(activated(int)), TQT_TQOBJECT(this), TQT_SLOT(slotHandleAttachment(int)));
02057 menu->exec( p ,0 );
02058 delete menu;
02059 }
02060
02061
02062 void KMReaderWin::setStyleDependantFrameWidth()
02063 {
02064 if ( !mBox )
02065 return;
02066
02067 int frameWidth;
02068 if( style().isA("KeramikStyle") )
02069 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1;
02070 else
02071 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
02072 if ( frameWidth < 0 )
02073 frameWidth = 0;
02074 if ( frameWidth != mBox->lineWidth() )
02075 mBox->setLineWidth( frameWidth );
02076 }
02077
02078
02079 void KMReaderWin::styleChange( TQStyle& oldStyle )
02080 {
02081 setStyleDependantFrameWidth();
02082 TQWidget::styleChange( oldStyle );
02083 }
02084
02085
02086 void KMReaderWin::slotHandleAttachment( int choice )
02087 {
02088 mAtmUpdate = true;
02089 partNode* node = mRootNode ? mRootNode->findId( mAtmCurrent ) : 0;
02090 if ( mAtmCurrentName.isEmpty() && node )
02091 mAtmCurrentName = tempFileUrlFromPartNode( node ).path();
02092 if ( choice < 7 ) {
02093 KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand(
02094 node, message(), mAtmCurrent, mAtmCurrentName,
02095 KMHandleAttachmentCommand::AttachmentAction( choice ), 0, this );
02096 connect( command, TQT_SIGNAL( showAttachment( int, const TQString& ) ),
02097 TQT_TQOBJECT(this), TQT_SLOT( slotAtmView( int, const TQString& ) ) );
02098 command->start();
02099 } else if ( choice == 7 ) {
02100 slotDeleteAttachment( node );
02101 } else if ( choice == 8 ) {
02102 slotEditAttachment( node );
02103 } else if ( choice == 9 ) {
02104 if ( !node ) return;
02105 KURL::List urls;
02106 KURL url = tempFileUrlFromPartNode( node );
02107 if (!url.isValid() ) return;
02108 urls.append( url );
02109 KURLDrag* drag = new KURLDrag( urls, this );
02110 TQApplication::clipboard()->setData( drag, TQClipboard::Clipboard );
02111 } else if ( choice == 10 ) {
02112 scrollToAttachment( node );
02113 }
02114 }
02115
02116
02117 void KMReaderWin::slotFind()
02118 {
02119 mViewer->findText();
02120 }
02121
02122
02123 void KMReaderWin::slotFindNext()
02124 {
02125 mViewer->findTextNext();
02126 }
02127
02128
02129 void KMReaderWin::slotToggleFixedFont()
02130 {
02131 mUseFixedFont = !mUseFixedFont;
02132 saveRelativePosition();
02133 update(true);
02134 }
02135
02136
02137
02138 void KMReaderWin::slotCopySelectedText()
02139 {
02140 kapp->clipboard()->setText( mViewer->selectedText() );
02141 }
02142
02143
02144
02145 void KMReaderWin::atmViewMsg( KMMessagePart* aMsgPart, int nodeId )
02146 {
02147 assert(aMsgPart!=0);
02148 KMMessage* msg = new KMMessage;
02149 msg->fromString(aMsgPart->bodyDecoded());
02150 assert(msg != 0);
02151 msg->setMsgSerNum( 0 );
02152
02153 msg->setParent( message()->parent() );
02154 msg->setUID(message()->UID());
02155 msg->setReadyToShow(true);
02156 KMReaderMainWin *win = new KMReaderMainWin();
02157 win->showMsg( overrideEncoding(), msg, message()->getMsgSerNum(), nodeId );
02158 win->show();
02159 }
02160
02161
02162 void KMReaderWin::setMsgPart( partNode * node ) {
02163 htmlWriter()->reset();
02164 mColorBar->hide();
02165 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
02166 htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
02167
02168 if ( node ) {
02169 ObjectTreeParser otp( this, 0, true );
02170 otp.parseObjectTree( node );
02171 }
02172
02173 htmlWriter()->queue( "</body></html>" );
02174 htmlWriter()->flush();
02175 }
02176
02177
02178 void KMReaderWin::setMsgPart( KMMessagePart* aMsgPart, bool aHTML,
02179 const TQString& aFileName, const TQString& pname )
02180 {
02181 KCursorSaver busy(KBusyPtr::busy());
02182 if (kasciistricmp(aMsgPart->typeStr(), "message")==0) {
02183
02184 KMMessage* msg = new KMMessage;
02185 assert(aMsgPart!=0);
02186 msg->fromString(aMsgPart->bodyDecoded());
02187 mMainWindow->setCaption(msg->subject());
02188 setMsg(msg, true);
02189 setAutoDelete(true);
02190 } else if (kasciistricmp(aMsgPart->typeStr(), "text")==0) {
02191 if (kasciistricmp(aMsgPart->subtypeStr(), "x-vcard") == 0) {
02192 showVCard( aMsgPart );
02193 return;
02194 }
02195 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
02196 htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
02197
02198 if (aHTML && (kasciistricmp(aMsgPart->subtypeStr(), "html")==0)) {
02199
02200 htmlWriter()->queue( aMsgPart->bodyToUnicode( overrideCodec() ) );
02201 mColorBar->setHtmlMode();
02202 } else {
02203 const TQCString str = aMsgPart->bodyDecoded();
02204 ObjectTreeParser otp( this );
02205 otp.writeBodyStr( str,
02206 overrideCodec() ? overrideCodec() : aMsgPart->codec(),
02207 message() ? message()->from() : TQString() );
02208 }
02209 htmlWriter()->queue("</body></html>");
02210 htmlWriter()->flush();
02211 mMainWindow->setCaption(i18n("View Attachment: %1").arg(pname));
02212 } else if (kasciistricmp(aMsgPart->typeStr(), "image")==0 ||
02213 (kasciistricmp(aMsgPart->typeStr(), "application")==0 &&
02214 kasciistricmp(aMsgPart->subtypeStr(), "postscript")==0))
02215 {
02216 if (aFileName.isEmpty()) return;
02217
02218 TQImageIO *iio = new TQImageIO();
02219 iio->setFileName(aFileName);
02220 if( iio->read() ) {
02221 TQImage img = iio->image();
02222 TQRect desk = TDEGlobalSettings::desktopGeometry(mMainWindow);
02223
02224 int width, height;
02225 if( img.width() < 50 )
02226 width = 70;
02227 else if( img.width()+20 < desk.width() )
02228 width = img.width()+20;
02229 else
02230 width = desk.width();
02231 if( img.height() < 50 )
02232 height = 70;
02233 else if( img.height()+20 < desk.height() )
02234 height = img.height()+20;
02235 else
02236 height = desk.height();
02237 mMainWindow->resize( width, height );
02238 }
02239
02240 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
02241 htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
02242 htmlWriter()->write( "<img src=\"file:" +
02243 KURL::encode_string( aFileName ) +
02244 "\" border=\"0\">\n"
02245 "</body></html>\n" );
02246 htmlWriter()->end();
02247 setCaption( i18n("View Attachment: %1").arg( pname ) );
02248 show();
02249 delete iio;
02250 } else {
02251 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
02252 htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
02253 htmlWriter()->queue( "<pre>" );
02254
02255 TQString str = aMsgPart->bodyDecoded();
02256
02257
02258 if( str.length() < (unsigned) aMsgPart->decodedSize() ) {
02259 str.prepend( i18n("[KMail: Attachment contains binary data. Trying to show first character.]",
02260 "[KMail: Attachment contains binary data. Trying to show first %n characters.]",
02261 str.length()) + TQChar('\n') );
02262 }
02263 htmlWriter()->queue( TQStyleSheet::escape( str ) );
02264 htmlWriter()->queue( "</pre>" );
02265 htmlWriter()->queue("</body></html>");
02266 htmlWriter()->flush();
02267 mMainWindow->setCaption(i18n("View Attachment: %1").arg(pname));
02268 }
02269
02270 }
02271
02272
02273
02274 void KMReaderWin::slotAtmView( int id, const TQString& name )
02275 {
02276 partNode* node = mRootNode ? mRootNode->findId( id ) : 0;
02277 if( node ) {
02278 mAtmCurrent = id;
02279 mAtmCurrentName = name;
02280 if ( mAtmCurrentName.isEmpty() )
02281 mAtmCurrentName = tempFileUrlFromPartNode( node ).path();
02282
02283 KMMessagePart& msgPart = node->msgPart();
02284 TQString pname = msgPart.fileName();
02285 if (pname.isEmpty()) pname=msgPart.name();
02286 if (pname.isEmpty()) pname=msgPart.contentDescription();
02287 if (pname.isEmpty()) pname="unnamed";
02288
02289 if (kasciistricmp(msgPart.typeStr(), "message")==0) {
02290 atmViewMsg( &msgPart,id );
02291 } else if ((kasciistricmp(msgPart.typeStr(), "text")==0) &&
02292 (kasciistricmp(msgPart.subtypeStr(), "x-vcard")==0)) {
02293 setMsgPart( &msgPart, htmlMail(), name, pname );
02294 } else {
02295 KMReaderMainWin *win = new KMReaderMainWin(&msgPart, htmlMail(),
02296 name, pname, overrideEncoding() );
02297 win->show();
02298 }
02299 }
02300 }
02301
02302
02303 void KMReaderWin::openAttachment( int id, const TQString & name )
02304 {
02305 mAtmCurrentName = name;
02306 mAtmCurrent = id;
02307
02308 TQString str, pname, cmd, fileName;
02309
02310 partNode* node = mRootNode ? mRootNode->findId( id ) : 0;
02311 if( !node ) {
02312 kdWarning(5006) << "KMReaderWin::openAttachment - could not find node " << id << endl;
02313 return;
02314 }
02315 if ( mAtmCurrentName.isEmpty() )
02316 mAtmCurrentName = tempFileUrlFromPartNode( node ).path();
02317
02318 KMMessagePart& msgPart = node->msgPart();
02319 if (kasciistricmp(msgPart.typeStr(), "message")==0)
02320 {
02321 atmViewMsg( &msgPart, id );
02322 return;
02323 }
02324
02325 TQCString contentTypeStr( msgPart.typeStr() + '/' + msgPart.subtypeStr() );
02326 KPIM::kAsciiToLower( contentTypeStr.data() );
02327
02328 if ( qstrcmp( contentTypeStr, "text/x-vcard" ) == 0 ) {
02329 showVCard( &msgPart );
02330 return;
02331 }
02332
02333
02334 KMimeType::Ptr mimetype;
02335
02336 mimetype = KMimeType::mimeType( TQString::fromLatin1( contentTypeStr ) );
02337 if ( mimetype->name() == "application/octet-stream" ) {
02338
02339 mimetype = KMimeType::findByPath( name, 0, true );
02340 }
02341 if ( ( mimetype->name() == "application/octet-stream" )
02342 && msgPart.isComplete() ) {
02343
02344
02345 mimetype = KMimeType::findByFileContent( name );
02346 }
02347
02348 KService::Ptr offer =
02349 KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
02350
02351 TQString open_text;
02352 TQString filenameText = msgPart.fileName();
02353 if ( filenameText.isEmpty() )
02354 filenameText = msgPart.name();
02355 if ( offer ) {
02356 open_text = i18n("&Open with '%1'").arg( offer->name() );
02357 } else {
02358 open_text = i18n("&Open With...");
02359 }
02360 const TQString text = i18n("Open attachment '%1'?\n"
02361 "Note that opening an attachment may compromise "
02362 "your system's security.")
02363 .arg( filenameText );
02364 const int choice = KMessageBox::questionYesNoCancel( this, text,
02365 i18n("Open Attachment?"), KStdGuiItem::saveAs(), open_text,
02366 TQString::fromLatin1("askSave") + mimetype->name() );
02367
02368 if( choice == KMessageBox::Yes ) {
02369 mAtmUpdate = true;
02370 KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand( node,
02371 message(), mAtmCurrent, mAtmCurrentName, KMHandleAttachmentCommand::Save,
02372 offer, this );
02373 connect( command, TQT_SIGNAL( showAttachment( int, const TQString& ) ),
02374 TQT_TQOBJECT(this), TQT_SLOT( slotAtmView( int, const TQString& ) ) );
02375 command->start();
02376 }
02377 else if( choice == KMessageBox::No ) {
02378 KMHandleAttachmentCommand::AttachmentAction action = ( offer ?
02379 KMHandleAttachmentCommand::Open : KMHandleAttachmentCommand::OpenWith );
02380 mAtmUpdate = true;
02381 KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand( node,
02382 message(), mAtmCurrent, mAtmCurrentName, action, offer, this );
02383 connect( command, TQT_SIGNAL( showAttachment( int, const TQString& ) ),
02384 TQT_TQOBJECT(this), TQT_SLOT( slotAtmView( int, const TQString& ) ) );
02385 command->start();
02386 } else {
02387 kdDebug(5006) << "Canceled opening attachment" << endl;
02388 }
02389 }
02390
02391
02392 void KMReaderWin::slotScrollUp()
02393 {
02394 static_cast<TQScrollView *>(mViewer->widget())->scrollBy(0, -10);
02395 }
02396
02397
02398
02399 void KMReaderWin::slotScrollDown()
02400 {
02401 static_cast<TQScrollView *>(mViewer->widget())->scrollBy(0, 10);
02402 }
02403
02404 bool KMReaderWin::atBottom() const
02405 {
02406 const TQScrollView *view = static_cast<const TQScrollView *>(mViewer->widget());
02407 return view->contentsY() + view->visibleHeight() >= view->contentsHeight();
02408 }
02409
02410
02411 void KMReaderWin::slotJumpDown()
02412 {
02413 TQScrollView *view = static_cast<TQScrollView *>(mViewer->widget());
02414 int offs = (view->clipper()->height() < 30) ? view->clipper()->height() : 30;
02415 view->scrollBy( 0, view->clipper()->height() - offs );
02416 }
02417
02418
02419 void KMReaderWin::slotScrollPrior()
02420 {
02421 static_cast<TQScrollView *>(mViewer->widget())->scrollBy(0, -(int)(height()*0.8));
02422 }
02423
02424
02425
02426 void KMReaderWin::slotScrollNext()
02427 {
02428 static_cast<TQScrollView *>(mViewer->widget())->scrollBy(0, (int)(height()*0.8));
02429 }
02430
02431
02432 void KMReaderWin::slotDocumentChanged()
02433 {
02434
02435 }
02436
02437
02438
02439 void KMReaderWin::slotTextSelected(bool)
02440 {
02441 TQString temp = mViewer->selectedText();
02442 kapp->clipboard()->setText(temp);
02443 }
02444
02445
02446 void KMReaderWin::selectAll()
02447 {
02448 mViewer->selectAll();
02449 }
02450
02451
02452 TQString KMReaderWin::copyText()
02453 {
02454 TQString temp = mViewer->selectedText();
02455 return temp;
02456 }
02457
02458
02459
02460 void KMReaderWin::slotDocumentDone()
02461 {
02462
02463 }
02464
02465
02466
02467 void KMReaderWin::setHtmlOverride(bool override)
02468 {
02469 mHtmlOverride = override;
02470 if (message())
02471 message()->setDecodeHTML(htmlMail());
02472 }
02473
02474
02475
02476 void KMReaderWin::setHtmlLoadExtOverride(bool override)
02477 {
02478 mHtmlLoadExtOverride = override;
02479
02480
02481 }
02482
02483
02484
02485 bool KMReaderWin::htmlMail()
02486 {
02487 return ((mHtmlMail && !mHtmlOverride) || (!mHtmlMail && mHtmlOverride));
02488 }
02489
02490
02491
02492 bool KMReaderWin::htmlLoadExternal()
02493 {
02494 return ((mHtmlLoadExternal && !mHtmlLoadExtOverride) ||
02495 (!mHtmlLoadExternal && mHtmlLoadExtOverride));
02496 }
02497
02498
02499
02500 void KMReaderWin::saveRelativePosition()
02501 {
02502 const TQScrollView * scrollview = static_cast<TQScrollView *>( mViewer->widget() );
02503 mSavedRelativePosition =
02504 static_cast<float>( scrollview->contentsY() ) / scrollview->contentsHeight();
02505 }
02506
02507
02508
02509 void KMReaderWin::update( bool force )
02510 {
02511 KMMessage* msg = message();
02512 if ( msg )
02513 setMsg( msg, force, true );
02514 }
02515
02516
02517
02518 KMMessage* KMReaderWin::message( KMFolder** aFolder ) const
02519 {
02520 KMFolder* tmpFolder;
02521 KMFolder*& folder = aFolder ? *aFolder : tmpFolder;
02522 folder = 0;
02523 if (mMessage)
02524 return mMessage;
02525 if (mLastSerNum) {
02526 KMMessage *message = 0;
02527 int index;
02528 KMMsgDict::instance()->getLocation( mLastSerNum, &folder, &index );
02529 if (folder )
02530 message = folder->getMsg( index );
02531 if (!message)
02532 kdWarning(5006) << "Attempt to reference invalid serial number " << mLastSerNum << "\n" << endl;
02533 return message;
02534 }
02535 return 0;
02536 }
02537
02538
02539
02540
02541 void KMReaderWin::slotUrlClicked()
02542 {
02543 KMMainWidget *mainWidget = dynamic_cast<KMMainWidget*>(mMainWindow);
02544 uint identity = 0;
02545 if ( message() && message()->parent() ) {
02546 identity = message()->parent()->identity();
02547 }
02548
02549 KMCommand *command = new KMUrlClickedCommand( mClickedUrl, identity, this,
02550 false, mainWidget );
02551 command->start();
02552 }
02553
02554
02555 void KMReaderWin::slotMailtoCompose()
02556 {
02557 KMCommand *command = new KMMailtoComposeCommand( mClickedUrl, message() );
02558 command->start();
02559 }
02560
02561
02562 void KMReaderWin::slotMailtoForward()
02563 {
02564 KMCommand *command = new KMMailtoForwardCommand( mMainWindow, mClickedUrl,
02565 message() );
02566 command->start();
02567 }
02568
02569
02570 void KMReaderWin::slotMailtoAddAddrBook()
02571 {
02572 KMCommand *command = new KMMailtoAddAddrBookCommand( mClickedUrl,
02573 mMainWindow);
02574 command->start();
02575 }
02576
02577
02578 void KMReaderWin::slotMailtoOpenAddrBook()
02579 {
02580 KMCommand *command = new KMMailtoOpenAddrBookCommand( mClickedUrl,
02581 mMainWindow );
02582 command->start();
02583 }
02584
02585
02586 void KMReaderWin::slotUrlCopy()
02587 {
02588
02589
02590 KMCommand *command =
02591 new KMUrlCopyCommand( mClickedUrl,
02592 dynamic_cast<KMMainWidget*>( mMainWindow ) );
02593 command->start();
02594 }
02595
02596
02597 void KMReaderWin::slotUrlOpen( const KURL &url )
02598 {
02599 if ( !url.isEmpty() )
02600 mClickedUrl = url;
02601 KMCommand *command = new KMUrlOpenCommand( mClickedUrl, this );
02602 command->start();
02603 }
02604
02605
02606 void KMReaderWin::slotAddBookmarks()
02607 {
02608 KMCommand *command = new KMAddBookmarksCommand( mClickedUrl, this );
02609 command->start();
02610 }
02611
02612
02613 void KMReaderWin::slotUrlSave()
02614 {
02615 KMCommand *command = new KMUrlSaveCommand( mClickedUrl, mMainWindow );
02616 command->start();
02617 }
02618
02619
02620 void KMReaderWin::slotMailtoReply()
02621 {
02622 KMCommand *command = new KMMailtoReplyCommand( mMainWindow, mClickedUrl,
02623 message(), copyText() );
02624 command->start();
02625 }
02626
02627
02628 partNode * KMReaderWin::partNodeFromUrl( const KURL & url ) {
02629 return mRootNode ? mRootNode->findId( msgPartFromUrl( url ) ) : 0 ;
02630 }
02631
02632 partNode * KMReaderWin::partNodeForId( int id ) {
02633 return mRootNode ? mRootNode->findId( id ) : 0 ;
02634 }
02635
02636
02637 KURL KMReaderWin::tempFileUrlFromPartNode( const partNode * node )
02638 {
02639 if (!node) return KURL();
02640 TQStringList::const_iterator it = mTempFiles.begin();
02641 TQStringList::const_iterator end = mTempFiles.end();
02642
02643 while ( it != end ) {
02644 TQString path = *it;
02645 it++;
02646 uint right = path.findRev('/');
02647 uint left = path.findRev('.', right);
02648
02649 bool ok;
02650 int res = path.mid(left + 1, right - left - 1).toInt(&ok);
02651 if ( res == node->nodeId() )
02652 return KURL( path );
02653 }
02654 return KURL();
02655 }
02656
02657
02658 void KMReaderWin::slotSaveAttachments()
02659 {
02660 mAtmUpdate = true;
02661 KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand( mMainWindow,
02662 message() );
02663 saveCommand->start();
02664 }
02665
02666
02667 void KMReaderWin::saveAttachment( const KURL &tempFileName )
02668 {
02669 mAtmCurrent = msgPartFromUrl( tempFileName );
02670 mAtmCurrentName = mClickedUrl.path();
02671 slotHandleAttachment( KMHandleAttachmentCommand::Save );
02672 }
02673
02674
02675 void KMReaderWin::slotSaveMsg()
02676 {
02677 KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( mMainWindow, message() );
02678
02679 if (saveCommand->url().isEmpty())
02680 delete saveCommand;
02681 else
02682 saveCommand->start();
02683 }
02684
02685 void KMReaderWin::slotIMChat()
02686 {
02687 KMCommand *command = new KMIMChatCommand( mClickedUrl, message() );
02688 command->start();
02689 }
02690
02691
02692 static TQString linkForNode( const DOM::Node &node )
02693 {
02694 try {
02695 if ( node.isNull() )
02696 return TQString();
02697
02698 const DOM::NamedNodeMap attributes = node.attributes();
02699 if ( !attributes.isNull() ) {
02700 const DOM::Node href = attributes.getNamedItem( DOM::DOMString( "href" ) );
02701 if ( !href.isNull() ) {
02702 return href.nodeValue().string();
02703 }
02704 }
02705 if ( !node.parentNode().isNull() ) {
02706 return linkForNode( node.parentNode() );
02707 } else {
02708 return TQString();
02709 }
02710 } catch ( DOM::DOMException &e ) {
02711 kdWarning(5006) << "Got an exception when trying to determine link under cursor!" << endl;
02712 return TQString();
02713 }
02714 }
02715
02716
02717 bool KMReaderWin::eventFilter( TQObject *, TQEvent *e )
02718 {
02719 if ( e->type() == TQEvent::MouseButtonPress ) {
02720 TQMouseEvent* me = TQT_TQMOUSEEVENT(e);
02721 if ( me->button() == Qt::LeftButton && ( me->state() & ShiftButton ) ) {
02722
02723 URLHandlerManager::instance()->handleShiftClick( mHoveredUrl, this );
02724 return true;
02725 }
02726
02727 if ( me->button() == Qt::LeftButton ) {
02728
02729 TQString imagePath;
02730 const DOM::Node nodeUnderMouse = mViewer->nodeUnderMouse();
02731 if ( !nodeUnderMouse.isNull() ) {
02732 const DOM::NamedNodeMap attributes = nodeUnderMouse.attributes();
02733 if ( !attributes.isNull() ) {
02734 const DOM::Node src = attributes.getNamedItem( DOM::DOMString( "src" ) );
02735 if ( !src.isNull() ) {
02736 imagePath = src.nodeValue().string();
02737 }
02738 }
02739 }
02740
02741 mCanStartDrag = URLHandlerManager::instance()->willHandleDrag( mHoveredUrl, imagePath, this );
02742 mLastClickPosition = me->pos();
02743 mLastClickImagePath = imagePath;
02744 }
02745 }
02746
02747 if ( e->type() == TQEvent::MouseButtonRelease ) {
02748 mCanStartDrag = false;
02749 }
02750
02751 if ( e->type() == TQEvent::MouseMove ) {
02752 TQMouseEvent* me = TQT_TQMOUSEEVENT( e );
02753
02754
02755
02756 slotUrlOn( linkForNode( mViewer->nodeUnderMouse() ) );
02757
02758 if ( ( mLastClickPosition - me->pos() ).manhattanLength() > TDEGlobalSettings::dndEventDelay() ) {
02759 if ( mCanStartDrag && ( !( mHoveredUrl.isEmpty() && mLastClickImagePath.isEmpty() ) ) ) {
02760 if ( URLHandlerManager::instance()->handleDrag( mHoveredUrl, mLastClickImagePath, this ) ) {
02761 mCanStartDrag = false;
02762 slotUrlOn( TQString() );
02763
02764
02765
02766
02767 TQMouseEvent mouseEvent( TQEvent::MouseButtonRelease, me->pos(), Qt::NoButton, Qt::NoButton );
02768 TQT_TQOBJECT( mViewer->view() )->eventFilter( mViewer->view()->viewport(),
02769 &mouseEvent );
02770 return true;
02771 }
02772 }
02773 }
02774 }
02775
02776
02777 return false;
02778 }
02779
02780 void KMReaderWin::fillCommandInfo( partNode *node, KMMessage **msg, int *nodeId )
02781 {
02782 Q_ASSERT( msg && nodeId );
02783
02784 if ( mSerNumOfOriginalMessage != 0 ) {
02785 KMFolder *folder = 0;
02786 int index = -1;
02787 KMMsgDict::instance()->getLocation( mSerNumOfOriginalMessage, &folder, &index );
02788 if ( folder && index != -1 )
02789 *msg = folder->getMsg( index );
02790
02791 if ( !( *msg ) ) {
02792 kdWarning( 5006 ) << "Unable to find the original message, aborting attachment deletion!" << endl;
02793 return;
02794 }
02795
02796 *nodeId = node->nodeId() + mNodeIdOffset;
02797 }
02798 else {
02799 *nodeId = node->nodeId();
02800 *msg = message();
02801 }
02802 }
02803
02804 void KMReaderWin::slotDeleteAttachment(partNode * node)
02805 {
02806 if ( KMessageBox::warningContinueCancel( this,
02807 i18n("Deleting an attachment might invalidate any digital signature on this message."),
02808 i18n("Delete Attachment"), KStdGuiItem::del(), "DeleteAttachmentSignatureWarning" )
02809 != KMessageBox::Continue ) {
02810 return;
02811 }
02812
02813 int nodeId = -1;
02814 KMMessage *msg = 0;
02815 fillCommandInfo( node, &msg, &nodeId );
02816 if ( msg && nodeId != -1 ) {
02817 KMDeleteAttachmentCommand* command = new KMDeleteAttachmentCommand( nodeId, msg, this );
02818 command->start();
02819 connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
02820 TQT_TQOBJECT(this), TQT_SLOT( updateReaderWin() ) );
02821 connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
02822 TQT_TQOBJECT(this), TQT_SLOT( disconnectMsgAdded() ) );
02823
02824
02825
02826
02827
02828
02829 const KMHeaders * const headers = KMKernel::self()->getKMMainWidget()->headers();
02830 connect( headers, TQT_SIGNAL( msgAddedToListView( TQListViewItem* ) ),
02831 TQT_TQOBJECT(this), TQT_SLOT( msgAdded( TQListViewItem* ) ) );
02832 }
02833
02834
02835 if ( mSerNumOfOriginalMessage != 0 && message() ) {
02836 message()->deleteBodyPart( node->nodeId() );
02837 update( true );
02838 }
02839 }
02840
02841 void KMReaderWin::msgAdded( TQListViewItem *item )
02842 {
02843
02844
02845
02846 disconnectMsgAdded();
02847 KMHeaders * const headers = KMKernel::self()->getKMMainWidget()->headers();
02848 headers->setCurrentItem( item );
02849 headers->clearSelection();
02850 headers->setSelected( item, true );
02851 }
02852
02853 void KMReaderWin::disconnectMsgAdded()
02854 {
02855 const KMHeaders *const headers = KMKernel::self()->getKMMainWidget()->headers();
02856 disconnect( headers, TQT_SIGNAL( msgAddedToListView( TQListViewItem* ) ),
02857 TQT_TQOBJECT(this), TQT_SLOT( msgAdded( TQListViewItem* ) ) );
02858 }
02859
02860 void KMReaderWin::slotEditAttachment(partNode * node)
02861 {
02862 if ( KMessageBox::warningContinueCancel( this,
02863 i18n("Modifying an attachment might invalidate any digital signature on this message."),
02864 i18n("Edit Attachment"), KGuiItem( i18n("Edit"), "edit" ), "EditAttachmentSignatureWarning" )
02865 != KMessageBox::Continue ) {
02866 return;
02867 }
02868
02869 int nodeId = -1;
02870 KMMessage *msg = 0;
02871 fillCommandInfo( node, &msg, &nodeId );
02872 if ( msg && nodeId != -1 ) {
02873 KMEditAttachmentCommand* command = new KMEditAttachmentCommand( nodeId, msg, this );
02874 command->start();
02875 }
02876
02877
02878 }
02879
02880 KMail::CSSHelper* KMReaderWin::cssHelper()
02881 {
02882 return mCSSHelper;
02883 }
02884
02885 bool KMReaderWin::decryptMessage() const
02886 {
02887 if ( !GlobalSettings::self()->alwaysDecrypt() )
02888 return mDecrytMessageOverwrite;
02889 return true;
02890 }
02891
02892 void KMReaderWin::scrollToAttachment( const partNode *node )
02893 {
02894 DOM::Document doc = mViewer->htmlDocument();
02895
02896
02897 mViewer->gotoAnchor( TQString::fromLatin1( "att%1" ).arg( node->nodeId() ) );
02898
02899
02900 const partNode *root = node->topLevelParent();
02901 for ( int i = 0; i <= root->totalChildCount() + 1; i++ ) {
02902 DOM::Element attachmentDiv = doc.getElementById( TQString( "attachmentDiv%1" ).arg( i + 1 ) );
02903 if ( !attachmentDiv.isNull() )
02904 attachmentDiv.removeAttribute( "style" );
02905 }
02906
02907
02908 if ( node->isDisplayedHidden() )
02909 return;
02910
02911
02912
02913
02914 DOM::Element attachmentDiv = doc.getElementById( TQString( "attachmentDiv%1" ).arg( node->nodeId() ) );
02915 if ( attachmentDiv.isNull() ) {
02916 kdWarning( 5006 ) << "Could not find attachment div for attachment " << node->nodeId() << endl;
02917 return;
02918 }
02919
02920 attachmentDiv.setAttribute( "style", TQString( "border:2px solid %1" )
02921 .arg( cssHelper()->pgpWarnColor().name() ) );
02922
02923
02924
02925 doc.updateRendering();
02926 }
02927
02928 void KMReaderWin::injectAttachments()
02929 {
02930
02931
02932 DOM::Document doc = mViewer->htmlDocument();
02933 DOM::Element injectionPoint = doc.getElementById( "attachmentInjectionPoint" );
02934 if ( injectionPoint.isNull() )
02935 return;
02936
02937 TQString imgpath( locate("data","kmail/pics/") );
02938 TQString visibility;
02939 TQString urlHandle;
02940 TQString imgSrc;
02941 if( !showAttachmentQuicklist() ) {
02942 urlHandle.append( "kmail:showAttachmentQuicklist" );
02943 imgSrc.append( "attachmentQuicklistClosed.png" );
02944 } else {
02945 urlHandle.append( "kmail:hideAttachmentQuicklist" );
02946 imgSrc.append( "attachmentQuicklistOpened.png" );
02947 }
02948
02949 TQString html = renderAttachments( mRootNode, TQApplication::palette().active().background() );
02950 if ( html.isEmpty() )
02951 return;
02952
02953 TQString link("");
02954 if ( headerStyle() == HeaderStyle::fancy() ) {
02955 link += "<div style=\"text-align: left;\"><a href=\"" + urlHandle + "\"><img src=\"" +
02956 imgpath + imgSrc + "\"/></a></div>";
02957 html.prepend( link );
02958 html.prepend( TQString::fromLatin1( "<div style=\"float:left;\">%1 </div>" ).
02959 arg( i18n( "Attachments:" ) ) );
02960 } else {
02961 link += "<div style=\"text-align: right;\"><a href=\"" + urlHandle + "\"><img src=\"" +
02962 imgpath + imgSrc + "\"/></a></div>";
02963 html.prepend( link );
02964 }
02965
02966 assert( injectionPoint.tagName() == "div" );
02967 static_cast<DOM::HTMLElement>( injectionPoint ).setInnerHTML( html );
02968 }
02969
02970 static TQColor nextColor( const TQColor & c )
02971 {
02972 int h, s, v;
02973 c.hsv( &h, &s, &v );
02974 return TQColor( (h + 50) % 360, TQMAX(s, 64), v, TQColor::Hsv );
02975 }
02976
02977 TQString KMReaderWin::renderAttachments(partNode * node, const TQColor &bgColor )
02978 {
02979 if ( !node )
02980 return TQString();
02981
02982 TQString html;
02983 if ( node->firstChild() ) {
02984 TQString subHtml = renderAttachments( node->firstChild(), nextColor( bgColor ) );
02985 if ( !subHtml.isEmpty() ) {
02986
02987 TQString visibility;
02988 if ( !showAttachmentQuicklist() ) {
02989 visibility.append( "display:none;" );
02990 }
02991
02992 TQString margin;
02993 if ( node != mRootNode || headerStyle() != HeaderStyle::enterprise() )
02994 margin = "padding:2px; margin:2px; ";
02995 TQString align = "left";
02996 if ( headerStyle() == HeaderStyle::enterprise() )
02997 align = "right";
02998 if ( node->msgPart().typeStr().lower() == "message" || node == mRootNode )
02999 html += TQString::fromLatin1("<div style=\"background:%1; %2"
03000 "vertical-align:middle; float:%3; %4\">").arg( bgColor.name() ).arg( margin )
03001 .arg( align ).arg( visibility );
03002 html += subHtml;
03003 if ( node->msgPart().typeStr().lower() == "message" || node == mRootNode )
03004 html += "</div>";
03005 }
03006 } else {
03007 partNode::AttachmentDisplayInfo info = node->attachmentDisplayInfo();
03008 if ( info.displayInHeader ) {
03009 html += "<div style=\"float:left;\">";
03010 html += TQString::fromLatin1( "<span style=\"white-space:nowrap; border-width: 0px; border-left-width: 5px; border-color: %1; 2px; border-left-style: solid;\">" ).arg( bgColor.name() );
03011 TQString fileName = writeMessagePartToTempFile( &node->msgPart(), node->nodeId() );
03012 TQString href = node->asHREF( "header" );
03013 html += TQString::fromLatin1( "<a href=\"" ) + href +
03014 TQString::fromLatin1( "\">" );
03015 html += "<img style=\"vertical-align:middle;\" src=\"" + info.icon + "\"/> ";
03016 if ( headerStyle() == HeaderStyle::enterprise() ) {
03017 TQFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
03018 TQFontMetrics fm( bodyFont );
03019 html += KStringHandler::rPixelSqueeze( info.label, fm, 140 );
03020 } else if ( headerStyle() == HeaderStyle::fancy() ) {
03021 TQFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
03022 TQFontMetrics fm( bodyFont );
03023 html += KStringHandler::rPixelSqueeze( info.label, fm, 640 );
03024 } else {
03025 html += info.label;
03026 }
03027 html += "</a></span></div> ";
03028 }
03029 }
03030
03031 html += renderAttachments( node->nextSibling(), nextColor ( bgColor ) );
03032 return html;
03033 }
03034
03035 using namespace KMail::Interface;
03036
03037 void KMReaderWin::setBodyPartMemento( const partNode * node, const TQCString & which, BodyPartMemento * memento )
03038 {
03039 const TQCString index = node->path() + ':' + which.lower();
03040
03041 const std::map<TQCString,BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( index );
03042 if ( it != mBodyPartMementoMap.end() && it->first == index ) {
03043
03044 if ( memento && memento == it->second )
03045 return;
03046
03047 delete it->second;
03048
03049 if ( memento ) {
03050 it->second = memento;
03051 }
03052 else {
03053 mBodyPartMementoMap.erase( it );
03054 }
03055
03056 } else {
03057 if ( memento ) {
03058 mBodyPartMementoMap.insert( it, std::make_pair( index, memento ) );
03059 }
03060 }
03061
03062 if ( Observable * o = memento ? memento->asObservable() : 0 )
03063 o->attach( this );
03064 }
03065
03066 BodyPartMemento * KMReaderWin::bodyPartMemento( const partNode * node, const TQCString & which ) const
03067 {
03068 const TQCString index = node->path() + ':' + which.lower();
03069 const std::map<TQCString,BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( index );
03070 if ( it == mBodyPartMementoMap.end() ) {
03071 return 0;
03072 }
03073 else {
03074 return it->second;
03075 }
03076 }
03077
03078 static void detach_and_delete( BodyPartMemento * memento, KMReaderWin * obs ) {
03079 if ( Observable * const o = memento ? memento->asObservable() : 0 )
03080 o->detach( obs );
03081 delete memento;
03082 }
03083
03084 void KMReaderWin::clearBodyPartMementos()
03085 {
03086 for ( std::map<TQCString,BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end() ; it != end ; ++it )
03087
03088
03089
03090
03091 detach_and_delete( it->second, this );
03092
03093 mBodyPartMementoMap.clear();
03094 }
03095
03096 #include "kmreaderwin.moc"
03097
03098