~ubuntu-branches/ubuntu/oneiric/kdepim/oneiric-updates

« back to all changes in this revision

Viewing changes to kmail/kmreaderwin.cpp

  • Committer: Package Import Robot
  • Author(s): Philip Muškovac
  • Date: 2011-06-28 19:33:24 UTC
  • mfrom: (0.2.13) (0.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20110628193324-8yvjs8sdv9rdoo6c
Tags: 4:4.7.0-0ubuntu1
* New upstream release
  - update install files
  - add missing kdepim-doc package to control file
  - Fix Vcs lines
  - kontact breaks/replaces korganizer << 4:4.6.80
  - tighten the dependency of kdepim-dev on libkdepim4 to fix lintian error

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: C++; c-file-style: "gnu" -*-
2
2
  This file is part of KMail, the KDE mail client.
3
3
  Copyright (c) 1997 Markus Wuebben <markus.wuebben@kde.org>
 
4
  Copyright (c) 2009 Laurent Montel <montel@kde.org>
4
5
 
5
6
  This program is free software; you can redistribute it and/or modify
6
7
  it under the terms of the GNU General Public License as published by
19
20
 
20
21
// define this to copy all html that is written to the readerwindow to
21
22
// filehtmlwriter.out in the current working directory
22
 
//#define KMAIL_READER_HTML_DEBUG 1
23
23
#include "kmreaderwin.h"
24
24
 
25
 
#include <config-kmail.h>
26
 
 
27
25
#include "globalsettings.h"
28
 
#include "kmversion.h"
29
26
#include "kmmainwidget.h"
30
27
#include "kmreadermainwin.h"
31
 
#include <kpimutils/kfileio.h>
32
 
#include "kmfolderindex.h"
 
28
#include "mailkernel.h"
 
29
 
 
30
#include "kdepim-version.h"
 
31
#include <kpimutils/email.h>
 
32
#include <libkdepim/addemailaddressjob.h>
 
33
#include <libkdepim/openemailaddressjob.h>
33
34
#include "kmcommands.h"
34
 
#include "kmmsgpartdlg.h"
35
 
#include "mailsourceviewer.h"
 
35
#include "mailcommon/mdnadvicedialog.h"
 
36
#include "mailcommon/sendmdnhandler.h"
36
37
#include <QByteArray>
37
 
#include <QImageReader>
38
 
#include <QCloseEvent>
39
 
#include <QEvent>
40
38
#include <QVBoxLayout>
41
 
#include <QResizeEvent>
42
 
#include <QMouseEvent>
43
 
#include <QScrollArea>
44
 
#include <QScrollBar>
45
 
#include <QSignalMapper>
46
 
using KMail::MailSourceViewer;
47
 
#include "partNode.h"
48
 
#include "kmmsgdict.h"
49
 
#include "messagesender.h"
50
 
#include "kcursorsaver.h"
51
 
#include "kmfolder.h"
52
 
#include "vcardviewer.h"
53
 
using KMail::VCardViewer;
54
 
#include "objecttreeparser.h"
55
 
using KMail::ObjectTreeParser;
56
 
#include "partmetadata.h"
57
 
using KMail::PartMetaData;
58
 
#include "attachmentstrategy.h"
59
 
using KMail::AttachmentStrategy;
60
 
#include "headerstrategy.h"
61
 
using KMail::HeaderStrategy;
62
 
#include "headerstyle.h"
63
 
using KMail::HeaderStyle;
64
 
#include "khtmlparthtmlwriter.h"
65
 
using KMail::HtmlWriter;
66
 
using KMail::KHtmlPartHtmlWriter;
67
 
#include "htmlstatusbar.h"
68
 
using KMail::HtmlStatusBar;
69
 
#include "folderjob.h"
70
 
using KMail::FolderJob;
71
 
#include "csshelper.h"
72
 
using KMail::CSSHelper;
73
 
#include "isubject.h"
74
 
using KMail::ISubject;
75
 
#include "urlhandlermanager.h"
76
 
using KMail::URLHandlerManager;
77
 
#include "interfaces/observable.h"
 
39
#include "messageviewer/headerstrategy.h"
 
40
#include "messageviewer/headerstyle.h"
 
41
#include "messageviewer/mailwebview.h"
 
42
#include "messageviewer/markmessagereadhandler.h"
 
43
#include "messageviewer/globalsettings.h"
 
44
 
 
45
#include "messageviewer/csshelper.h"
 
46
using MessageViewer::CSSHelper;
78
47
#include "util.h"
79
 
#include <kicon.h>
80
 
#include "broadcaststatus.h"
81
 
#include "attachmentdialog.h"
 
48
//#include "messageviewer/attachmentdialog.h"
82
49
#include "stringutil.h"
83
50
 
84
51
#include <kmime/kmime_mdn.h>
85
52
using namespace KMime;
86
 
#ifdef KMAIL_READER_HTML_DEBUG
87
 
#include "filehtmlwriter.h"
88
 
using KMail::FileHtmlWriter;
89
 
#include "teehtmlwriter.h"
90
 
using KMail::TeeHtmlWriter;
91
 
#endif
92
 
 
93
 
#include <mimelib/mimepp.h>
94
 
#include <mimelib/body.h>
95
 
#include <mimelib/utility.h>
96
 
 
97
 
#include "kleo/specialjob.h"
98
 
#include "kleo/cryptobackend.h"
99
 
#include "kleo/cryptobackendfactory.h"
 
53
 
 
54
#include "messageviewer/viewer.h"
 
55
using namespace MessageViewer;
 
56
#include "messageviewer/attachmentstrategy.h"
 
57
#include "messagecomposer/messagesender.h"
 
58
#include "messagecomposer/messagefactory.h"
 
59
using MessageComposer::MessageFactory;
 
60
 
 
61
#include "messagecore/messagehelpers.h"
 
62
 
100
63
 
101
64
// KABC includes
102
65
#include <kabc/addressee.h>
103
66
#include <kabc/vcardconverter.h>
104
67
 
105
 
// khtml headers
106
 
#include <khtml_part.h>
107
 
#include <khtmlview.h> // So that we can get rid of the frames
108
 
#include <dom/html_element.h>
109
 
#include <dom/html_block.h>
110
 
#include <dom/html_document.h>
111
 
#include <dom/dom_string.h>
112
68
 
113
69
#include <kde_file.h>
114
 
#include <kactionmenu.h>
115
 
// for the click on attachment stuff (dnaber):
116
 
#include <kcharsets.h>
117
 
#include <kmenu.h>
118
 
#include <kstandarddirs.h>  // Sven's : for access and getpid
119
70
#include <kdebug.h>
120
 
#include <kfiledialog.h>
121
71
#include <klocale.h>
122
 
#include <kmessagebox.h>
123
 
#include <kmimetypetrader.h>
124
 
#include <kglobalsettings.h>
125
 
#include <krun.h>
126
 
#include <ktemporaryfile.h>
127
 
#include <kdialog.h>
128
72
#include <kaction.h>
129
 
#include <kfontaction.h>
 
73
#include <kicon.h>
130
74
#include <kiconloader.h>
131
75
#include <kcodecs.h>
132
 
#include <kascii.h>
133
 
#include <kselectaction.h>
134
76
#include <kstandardaction.h>
135
77
#include <ktoggleaction.h>
136
78
#include <kconfiggroup.h>
137
79
 
138
80
#include <QClipboard>
139
 
#include <QCursor>
140
 
#include <QTextCodec>
141
 
#include <QLayout>
142
 
#include <QLabel>
143
 
#include <QSplitter>
144
 
#include <QStyle>
145
81
 
146
82
// X headers...
147
83
#undef Never
150
86
#include <unistd.h>
151
87
#include <stdlib.h>
152
88
#include <sys/stat.h>
153
 
#include <errno.h>
154
89
#include <stdio.h>
155
90
#include <ctype.h>
156
91
#include <string.h>
157
 
 
158
 
#ifdef HAVE_PATHS_H
159
 
#include <paths.h>
160
 
#include <kvbox.h>
161
 
#include <QTextDocument>
162
 
#endif
 
92
#include <mailutil.h>
163
93
 
164
94
using namespace KMail;
165
 
 
166
 
// This function returns the complete data that were in this
167
 
// message parts - *after* all encryption has been removed that
168
 
// could be removed.
169
 
// - This is used to store the message in decrypted form.
170
 
void KMReaderWin::objectTreeToDecryptedMsg( partNode* node,
171
 
                                            QByteArray& resultingData,
172
 
                                            KMMessage& theMessage,
173
 
                                            bool weAreReplacingTheRootNode,
174
 
                                            int recCount )
175
 
{
176
 
  kDebug() << "-------------------------------------------------";
177
 
  kDebug() << "START" << "(" << recCount << ")";
178
 
  if( node ) {
179
 
 
180
 
    kDebug(5006) << node->typeString() << '/' << node->subTypeString();
181
 
 
182
 
    partNode* curNode = node;
183
 
    partNode* dataNode = curNode;
184
 
    partNode * child = node->firstChild();
185
 
    const bool bIsMultipart = node->type() == DwMime::kTypeMultipart;
186
 
    bool bKeepPartAsIs = false;
187
 
 
188
 
    switch( curNode->type() ) {
189
 
      case DwMime::kTypeMultipart: {
190
 
          switch( curNode->subType() ) {
191
 
          case DwMime::kSubtypeSigned: {
192
 
              bKeepPartAsIs = true;
193
 
            }
194
 
            break;
195
 
          case DwMime::kSubtypeEncrypted: {
196
 
              if ( child )
197
 
                dataNode = child;
198
 
            }
199
 
            break;
200
 
          }
201
 
        }
202
 
        break;
203
 
      case DwMime::kTypeMessage: {
204
 
          switch( curNode->subType() ) {
205
 
          case DwMime::kSubtypeRfc822: {
206
 
              if ( child )
207
 
                dataNode = child;
208
 
            }
209
 
            break;
210
 
          }
211
 
        }
212
 
        break;
213
 
      case DwMime::kTypeApplication: {
214
 
          switch( curNode->subType() ) {
215
 
          case DwMime::kSubtypeOctetStream: {
216
 
              if ( child )
217
 
                dataNode = child;
218
 
            }
219
 
            break;
220
 
          case DwMime::kSubtypePkcs7Signature: {
221
 
              // note: subtype Pkcs7Signature specifies a signature part
222
 
              //       which we do NOT want to remove!
223
 
              bKeepPartAsIs = true;
224
 
            }
225
 
            break;
226
 
          case DwMime::kSubtypePkcs7Mime: {
227
 
              // note: subtype Pkcs7Mime can also be signed
228
 
              //       and we do NOT want to remove the signature!
229
 
              if ( child && curNode->encryptionState() != KMMsgNotEncrypted )
230
 
                dataNode = child;
231
 
            }
232
 
            break;
233
 
          }
234
 
        }
235
 
        break;
236
 
    }
237
 
 
238
 
 
239
 
    DwHeaders& rootHeaders( theMessage.headers() );
240
 
    DwBodyPart * part = dataNode->dwPart() ? dataNode->dwPart() : 0;
241
 
    DwHeaders * headers(
242
 
        (part && part->hasHeaders())
243
 
        ? &part->Headers()
244
 
        : (  (weAreReplacingTheRootNode || !dataNode->parentNode())
245
 
            ? &rootHeaders
246
 
            : 0 ) );
247
 
    if( dataNode == curNode ) {
248
 
      kDebug() << "dataNode == curNode:  Save curNode without replacing it.";
249
 
 
250
 
      // A) Store the headers of this part IF curNode is not the root node
251
 
      //    AND we are not replacing a node that already *has* replaced
252
 
      //    the root node in previous recursion steps of this function...
253
 
      if( headers ) {
254
 
        if( dataNode->parentNode() && !weAreReplacingTheRootNode ) {
255
 
          kDebug() << "dataNode is NOT replacing the root node:  Store the headers.";
256
 
          resultingData += headers->AsString().c_str();
257
 
        } else if( weAreReplacingTheRootNode && part && part->hasHeaders() ){
258
 
          kDebug() << "dataNode replace the root node:  Do NOT store the headers but change";
259
 
          kDebug() << "                                the Message's headers accordingly.";
260
 
          kDebug() << "             old Content-Type =" << rootHeaders.ContentType().AsString().c_str();
261
 
          kDebug() << "             new Content-Type =" << headers->ContentType(   ).AsString().c_str();
262
 
          rootHeaders.ContentType()             = headers->ContentType();
263
 
          theMessage.setContentTransferEncodingStr(
264
 
              headers->HasContentTransferEncoding()
265
 
            ? headers->ContentTransferEncoding().AsString().c_str()
266
 
            : "" );
267
 
          rootHeaders.ContentDescription() = headers->ContentDescription();
268
 
          rootHeaders.ContentDisposition() = headers->ContentDisposition();
269
 
          theMessage.setNeedsAssembly();
270
 
        }
271
 
      }
272
 
 
273
 
      if ( bKeepPartAsIs ) {
274
 
        resultingData += dataNode->encodedBody();
275
 
      } else {
276
 
 
277
 
        // B) Store the body of this part.
278
 
        if( headers && bIsMultipart && dataNode->firstChild() )  {
279
 
          kDebug() << "is valid Multipart, processing children:";
280
 
          QByteArray boundary = headers->ContentType().Boundary().c_str();
281
 
          curNode = dataNode->firstChild();
282
 
          // store children of multipart
283
 
          while( curNode ) {
284
 
            kDebug() << "--boundary";
285
 
            if( resultingData.size() &&
286
 
                ( '\n' != resultingData.at( resultingData.size()-1 ) ) )
287
 
              resultingData += '\n';
288
 
            resultingData += '\n';
289
 
            resultingData += "--";
290
 
            resultingData += boundary;
291
 
            resultingData += '\n';
292
 
            // note: We are processing a harmless multipart that is *not*
293
 
            //       to be replaced by one of it's children, therefor
294
 
            //       we set their doStoreHeaders to true.
295
 
            objectTreeToDecryptedMsg( curNode,
296
 
                                      resultingData,
297
 
                                      theMessage,
298
 
                                      false,
299
 
                                      recCount + 1 );
300
 
            curNode = curNode->nextSibling();
301
 
          }
302
 
          kDebug() << "--boundary--";
303
 
          resultingData += "\n--";
304
 
          resultingData += boundary;
305
 
          resultingData += "--\n\n";
306
 
          kDebug() << "Multipart processing children - DONE";
307
 
        } else if( part ){
308
 
          // store simple part
309
 
          kDebug() << "is Simple part or invalid Multipart, storing body data .. DONE";
310
 
          resultingData += part->Body().AsString().c_str();
311
 
        }
312
 
      }
313
 
    } else {
314
 
      kDebug() << "dataNode != curNode:  Replace curNode by dataNode.";
315
 
      bool rootNodeReplaceFlag = weAreReplacingTheRootNode || !curNode->parentNode();
316
 
      if( rootNodeReplaceFlag ) {
317
 
        kDebug() << "                     Root node will be replaced.";
318
 
      } else {
319
 
        kDebug() << "                     Root node will NOT be replaced.";
320
 
      }
321
 
      // store special data to replace the current part
322
 
      // (e.g. decrypted data or embedded RfC 822 data)
323
 
      objectTreeToDecryptedMsg( dataNode,
324
 
                                resultingData,
325
 
                                theMessage,
326
 
                                rootNodeReplaceFlag,
327
 
                                recCount + 1 );
328
 
    }
329
 
  }
330
 
  kDebug() << "END" << "(" << recCount << ")";
331
 
}
332
 
 
333
 
 
334
 
/*
335
 
 ===========================================================================
336
 
 
337
 
 
338
 
        E N D    O F     T E M P O R A R Y     M I M E     C O D E
339
 
 
340
 
 
341
 
 ===========================================================================
342
 
*/
343
 
 
344
 
 
345
 
 
346
 
 
347
 
 
348
 
 
349
 
 
350
 
 
351
 
 
352
 
 
353
 
 
354
 
void KMReaderWin::createWidgets() {
355
 
  QVBoxLayout * vlay = new QVBoxLayout( this );
356
 
  vlay->setMargin( 0 );
357
 
  mSplitter = new QSplitter( Qt::Vertical, this );
358
 
  mSplitter->setObjectName( "mSplitter" );
359
 
  mSplitter->setChildrenCollapsible( false );
360
 
  vlay->addWidget( mSplitter );
361
 
  mMimePartTree = new KMMimePartTree( this, mSplitter );
362
 
  mMimePartTree->setObjectName( "mMimePartTree" );
363
 
  mBox = new KHBox( mSplitter );
364
 
  setStyleDependantFrameWidth();
365
 
  mBox->setFrameStyle( mMimePartTree->frameStyle() );
366
 
  mColorBar = new HtmlStatusBar( mBox );
367
 
  mColorBar->setObjectName( "mColorBar" );
368
 
  connect( mColorBar, SIGNAL( clicked() ),
369
 
           this, SLOT( slotToggleHtmlMode() ) );
370
 
  mViewer = new KHTMLPart( mBox );
371
 
  mViewer->setObjectName( "mViewer" );
372
 
  // Remove the shortcut for the selectAll action from khtml part. It's redefined to
373
 
  // CTRL-SHIFT-A in kmail and clashes with kmails CTRL-A action.
374
 
  KAction *selectAll = qobject_cast<KAction*>(
375
 
          mViewer->actionCollection()->action( "selectAll" ) );
376
 
  if ( selectAll ) {
377
 
    selectAll->setShortcut( KShortcut() );
378
 
  } else {
379
 
    kDebug() << "Failed to find khtml's selectAll action to remove it's shortcut";
380
 
  }
381
 
  // Remove the shortcut for the find action from khtml part. It's redefined to
382
 
  // CTRL-F in kmail and clashes with khtml CTRL-F action.
383
 
  KAction *afind = qobject_cast<KAction*>(
384
 
          mViewer->actionCollection()->action( "find" ) );
385
 
  if ( afind ) {
386
 
    afind->setShortcut( KShortcut() );
387
 
  } else {
388
 
    kDebug() << "Failed to find khtml's find action to remove it's shortcut";
389
 
  }
390
 
 
391
 
  mSplitter->setStretchFactor( mSplitter->indexOf(mMimePartTree), 0 );
392
 
  mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
393
 
}
394
 
 
395
 
const int KMReaderWin::delay = 150;
 
95
using namespace MailCommon;
396
96
 
397
97
//-----------------------------------------------------------------------------
398
98
KMReaderWin::KMReaderWin(QWidget *aParent,
400
100
                         KActionCollection* actionCollection,
401
101
                         Qt::WindowFlags aFlags )
402
102
  : QWidget(aParent, aFlags ),
403
 
    mSerNumOfOriginalMessage( 0 ),
404
 
    mNodeIdOffset( -1 ),
405
 
    mAttachmentStrategy( 0 ),
406
 
    mHeaderStrategy( 0 ),
407
 
    mHeaderStyle( 0 ),
408
 
    mUpdateReaderWinTimer( 0 ),
409
 
    mResizeTimer( 0 ),
410
 
    mDelayedMarkTimer( 0 ),
411
 
    mOldGlobalOverrideEncoding( "---" ), // init with dummy value
412
 
    mCSSHelper( 0 ),
413
 
    mRootNode( 0 ),
414
103
    mMainWindow( mainWindow ),
415
104
    mActionCollection( actionCollection ),
416
105
    mMailToComposeAction( 0 ),
418
107
    mMailToForwardAction( 0 ),
419
108
    mAddAddrBookAction( 0 ),
420
109
    mOpenAddrBookAction( 0 ),
421
 
    mCopyAction( 0 ),
422
 
    mCopyURLAction( 0 ),
423
 
    mUrlOpenAction( 0 ),
424
110
    mUrlSaveAsAction( 0 ),
425
 
    mAddBookmarksAction( 0 ),
426
 
    mSelectAllAction( 0 ),
427
 
    mScrollUpAction( 0 ),
428
 
    mScrollDownAction( 0 ),
429
 
    mScrollUpMoreAction( 0 ),
430
 
    mScrollDownMoreAction( 0 ),
431
 
    mToggleMimePartTreeAction( 0 ),
432
 
    mSelectEncodingAction( 0 ),
433
 
    mToggleFixFontAction( 0 ),
434
 
    mToggleDisplayModeAction( 0 ),
435
 
    mCanStartDrag( false ),
436
 
    mHtmlWriter( 0 ),
437
 
    mSavedRelativePosition( 0 ),
438
 
    mDecrytMessageOverwrite( false ),
439
 
    mShowSignatureDetails( false ),
440
 
    mShowAttachmentQuicklist( true ),
441
 
    mShowFullToAddressList( false ),
442
 
    mShowFullCcAddressList( false )
 
111
    mAddBookmarksAction( 0 )
443
112
{
444
 
  mUpdateReaderWinTimer.setObjectName( "mUpdateReaderWinTimer" );
445
 
  mDelayedMarkTimer.setObjectName( "mDelayedMarkTimer" );
446
 
  mResizeTimer.setObjectName( "mResizeTimer" );
447
 
 
448
 
  mExternalWindow  = ( aParent == mainWindow );
449
 
  mSplitterSizes << 180 << 100;
450
 
  mAutoDelete = false;
451
 
  mLastSerNum = 0;
452
 
  mWaitingForSerNum = 0;
453
 
  mMessage = 0;
454
 
  mMsgDisplay = true;
455
 
  mPrinting = false;
456
 
  mAtmUpdate = false;
457
 
 
458
 
  createWidgets();
459
113
  createActions();
460
 
  initHtmlWidget();
 
114
  QVBoxLayout * vlay = new QVBoxLayout( this );
 
115
  vlay->setMargin( 0 );
 
116
  mViewer = new Viewer( this, mainWindow, mActionCollection );
 
117
  mViewer->setAppName( "KMail" );
 
118
  connect( mViewer, SIGNAL(urlClicked( const Akonadi::Item &, const KUrl & ) ),
 
119
           this, SLOT( slotUrlClicked( const Akonadi::Item &, const KUrl& ) ) );
 
120
  connect( mViewer, SIGNAL( requestConfigSync() ), kmkernel, SLOT( slotRequestConfigSync() ), Qt::QueuedConnection ); // happens anyway on shutdown, so we can skip it there with using a queued connection
 
121
  connect( mViewer, SIGNAL( showReader( KMime::Content* , bool, const QString& ) ),
 
122
           this, SLOT( slotShowReader( KMime::Content* , bool, const QString& ) ) );
 
123
  connect( mViewer, SIGNAL( showMessage(KMime::Message::Ptr, const QString&) ),
 
124
           this, SLOT( slotShowMessage(KMime::Message::Ptr, const QString& ) ) );
 
125
  connect( mViewer, SIGNAL( showStatusBarMessage( const QString & ) ),
 
126
           this, SIGNAL( showStatusBarMessage( const QString & ) ) );
 
127
  connect( mViewer, SIGNAL( deleteMessage( Akonadi::Item ) ),
 
128
           this, SLOT( slotDeleteMessage( Akonadi::Item ) ) );
 
129
 
 
130
  mViewer->addMessageLoadedHandler( new MessageViewer::MarkMessageReadHandler( this ) );
 
131
  mViewer->addMessageLoadedHandler( new MailCommon::SendMdnHandler( kmkernel, this ) );
 
132
 
 
133
  vlay->addWidget( mViewer );
461
134
  readConfig();
462
135
 
463
 
  mHtmlOverride = false;
464
 
  mHtmlLoadExtOverride = false;
465
 
 
466
 
  mLevelQuote = GlobalSettings::self()->collapseQuoteLevelSpin() - 1;
467
 
 
468
 
  mResizeTimer.setSingleShot( true );
469
 
  connect( &mResizeTimer, SIGNAL(timeout()),
470
 
           this, SLOT(slotDelayedResize()) );
471
 
 
472
 
  mDelayedMarkTimer.setSingleShot( true );
473
 
  connect( &mDelayedMarkTimer, SIGNAL(timeout()),
474
 
           this, SLOT(slotTouchMessage()) );
475
 
 
476
 
  mUpdateReaderWinTimer.setSingleShot( true );
477
 
  connect( &mUpdateReaderWinTimer, SIGNAL(timeout()),
478
 
           this, SLOT(updateReaderWin()) );
479
 
 
480
 
  setMsg( 0, false );
481
136
}
482
137
 
483
138
void KMReaderWin::createActions()
486
141
  if ( !ac ) {
487
142
    return;
488
143
  }
489
 
 
490
 
  KToggleAction *raction = 0;
491
 
 
492
 
  // header style
493
 
  KActionMenu *headerMenu  = new KActionMenu(i18nc("View->", "&Headers"), this);
494
 
  ac->addAction("view_headers", headerMenu );
495
 
  headerMenu->setHelpText( i18n("Choose display style of message headers") );
496
 
 
497
 
  connect( headerMenu, SIGNAL(triggered(bool)),
498
 
           this, SLOT(slotCycleHeaderStyles()) );
499
 
 
500
 
  QActionGroup *group = new QActionGroup( this );
501
 
  raction = new KToggleAction( i18nc("View->headers->", "&Enterprise Headers"), this);
502
 
  ac->addAction( "view_headers_enterprise", raction );
503
 
  connect( raction, SIGNAL(triggered(bool)), SLOT(slotEnterpriseHeaders()) );
504
 
  raction->setHelpText( i18n("Show the list of headers in Enterprise style") );
505
 
  group->addAction( raction );
506
 
  headerMenu->addAction( raction );
507
 
 
508
 
  raction  = new KToggleAction(i18nc("View->headers->", "&Fancy Headers"), this);
509
 
  ac->addAction("view_headers_fancy", raction );
510
 
  connect(raction, SIGNAL(triggered(bool) ), SLOT(slotFancyHeaders()));
511
 
  raction->setHelpText( i18n("Show the list of headers in a fancy format") );
512
 
  group->addAction( raction );
513
 
  headerMenu->addAction( raction );
514
 
 
515
 
  raction  = new KToggleAction(i18nc("View->headers->", "&Brief Headers"), this);
516
 
  ac->addAction("view_headers_brief", raction );
517
 
  connect(raction, SIGNAL(triggered(bool) ), SLOT(slotBriefHeaders()));
518
 
  raction->setHelpText( i18n("Show brief list of message headers") );
519
 
  group->addAction( raction );
520
 
  headerMenu->addAction( raction );
521
 
 
522
 
  raction  = new KToggleAction(i18nc("View->headers->", "&Standard Headers"), this);
523
 
  ac->addAction("view_headers_standard", raction );
524
 
  connect(raction, SIGNAL(triggered(bool) ), SLOT(slotStandardHeaders()));
525
 
  raction->setHelpText( i18n("Show standard list of message headers") );
526
 
  group->addAction( raction );
527
 
  headerMenu->addAction( raction );
528
 
 
529
 
  raction  = new KToggleAction(i18nc("View->headers->", "&Long Headers"), this);
530
 
  ac->addAction("view_headers_long", raction );
531
 
  connect(raction, SIGNAL(triggered(bool) ), SLOT(slotLongHeaders()));
532
 
  raction->setHelpText( i18n("Show long list of message headers") );
533
 
  group->addAction( raction );
534
 
  headerMenu->addAction( raction );
535
 
 
536
 
  raction  = new KToggleAction(i18nc("View->headers->", "&All Headers"), this);
537
 
  ac->addAction("view_headers_all", raction );
538
 
  connect(raction, SIGNAL(triggered(bool) ), SLOT(slotAllHeaders()));
539
 
  raction->setHelpText( i18n("Show all message headers") );
540
 
  group->addAction( raction );
541
 
  headerMenu->addAction( raction );
542
 
 
543
 
  // attachment style
544
 
  KActionMenu *attachmentMenu  = new KActionMenu(i18nc("View->", "&Attachments"), this);
545
 
  ac->addAction("view_attachments", attachmentMenu );
546
 
  attachmentMenu->setHelpText( i18n("Choose display style of attachments") );
547
 
  connect( attachmentMenu, SIGNAL(triggered(bool)),
548
 
           this, SLOT(slotCycleAttachmentStrategy()) );
549
 
 
550
 
  group = new QActionGroup( this );
551
 
  raction  = new KToggleAction(i18nc("View->attachments->", "&As Icons"), this);
552
 
  ac->addAction("view_attachments_as_icons", raction );
553
 
  connect(raction, SIGNAL(triggered(bool) ), SLOT(slotIconicAttachments()));
554
 
  raction->setHelpText( i18n("Show all attachments as icons. Click to see them.") );
555
 
  group->addAction( raction );
556
 
  attachmentMenu->addAction( raction );
557
 
 
558
 
  raction  = new KToggleAction(i18nc("View->attachments->", "&Smart"), this);
559
 
  ac->addAction("view_attachments_smart", raction );
560
 
  connect(raction, SIGNAL(triggered(bool) ), SLOT(slotSmartAttachments()));
561
 
  raction->setHelpText( i18n("Show attachments as suggested by sender.") );
562
 
  group->addAction( raction );
563
 
  attachmentMenu->addAction( raction );
564
 
 
565
 
  raction  = new KToggleAction(i18nc("View->attachments->", "&Inline"), this);
566
 
  ac->addAction("view_attachments_inline", raction );
567
 
  connect(raction, SIGNAL(triggered(bool) ), SLOT(slotInlineAttachments()));
568
 
  raction->setHelpText( i18n("Show all attachments inline (if possible)") );
569
 
  group->addAction( raction );
570
 
  attachmentMenu->addAction( raction );
571
 
 
572
 
  raction  = new KToggleAction(i18nc("View->attachments->", "&Hide"), this);
573
 
  ac->addAction("view_attachments_hide", raction );
574
 
  connect(raction, SIGNAL(triggered(bool) ), SLOT(slotHideAttachments()));
575
 
  raction->setHelpText( i18n("Do not show attachments in the message viewer") );
576
 
  group->addAction( raction );
577
 
  attachmentMenu->addAction( raction );
578
 
 
579
 
  // Set Encoding submenu
580
 
  mSelectEncodingAction  = new KSelectAction(KIcon("character-set"), i18n("&Set Encoding"), this);
581
 
  mSelectEncodingAction->setToolBarMode( KSelectAction::MenuMode );
582
 
  ac->addAction("encoding", mSelectEncodingAction );
583
 
  connect(mSelectEncodingAction,SIGNAL( triggered(int)),
584
 
          SLOT( slotSetEncoding() ));
585
 
  QStringList encodings = KMMsgBase::supportedEncodings( false );
586
 
  encodings.prepend( i18n( "Auto" ) );
587
 
  mSelectEncodingAction->setItems( encodings );
588
 
  mSelectEncodingAction->setCurrentItem( 0 );
589
 
 
590
144
  //
591
145
  // Message Menu
592
146
  //
593
 
 
594
147
  // new message to
595
148
  mMailToComposeAction = new KAction( KIcon( "mail-message-new" ),
596
149
                                      i18n( "New Message To..." ), this );
625
178
  ac->addAction( "openin_addr_book", mOpenAddrBookAction );
626
179
  connect( mOpenAddrBookAction, SIGNAL(triggered(bool)),
627
180
           SLOT(slotMailtoOpenAddrBook()) );
628
 
 
629
 
  // copy selected text to clipboard
630
 
  mCopyAction = ac->addAction( KStandardAction::Copy, "kmail_copy", this,
631
 
                               SLOT(slotCopySelectedText()) );
632
 
 
633
 
  // copy all text to clipboard
634
 
  mSelectAllAction  = new KAction(i18n("Select All Text"), this);
635
 
  ac->addAction("mark_all_text", mSelectAllAction );
636
 
  connect(mSelectAllAction, SIGNAL(triggered(bool) ), SLOT(selectAll()));
637
 
  mSelectAllAction->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_T ) );
638
 
 
639
 
  // copy Email address to clipboard
640
 
  mCopyURLAction = new KAction( KIcon( "edit-copy" ),
641
 
                                i18n( "Copy Link Address" ), this );
642
 
  ac->addAction( "copy_url", mCopyURLAction );
643
 
  connect( mCopyURLAction, SIGNAL(triggered(bool)), SLOT(slotUrlCopy()) );
644
 
 
645
 
  // find text
646
 
  KAction *action = new KAction(KIcon("edit-find"), i18n("&Find in Message..."), this);
647
 
  ac->addAction("find_in_messages", action );
648
 
  connect(action, SIGNAL(triggered(bool)), SLOT(slotFind()));
649
 
  action->setShortcut(KStandardShortcut::find());
650
 
 
651
 
  // open URL
652
 
  mUrlOpenAction = new KAction( KIcon( "document-open" ), i18n( "Open URL" ), this );
653
 
  ac->addAction( "open_url", mUrlOpenAction );
654
 
  connect( mUrlOpenAction, SIGNAL(triggered(bool)), SLOT(slotUrlOpen()) );
655
 
 
656
181
  // bookmark message
657
182
  mAddBookmarksAction = new KAction( KIcon( "bookmark-new" ), i18n( "Bookmark This Link" ), this );
658
183
  ac->addAction( "add_bookmarks", mAddBookmarksAction );
664
189
  ac->addAction( "saveas_url", mUrlSaveAsAction );
665
190
  connect( mUrlSaveAsAction, SIGNAL(triggered(bool)), SLOT(slotUrlSave()) );
666
191
 
667
 
  // use fixed font
668
 
  mToggleFixFontAction = new KToggleAction( i18n( "Use Fi&xed Font" ), this );
669
 
  ac->addAction( "toggle_fixedfont", mToggleFixFontAction );
670
 
  connect( mToggleFixFontAction, SIGNAL(triggered(bool)), SLOT(slotToggleFixedFont()) );
671
 
  mToggleFixFontAction->setShortcut( QKeySequence( Qt::Key_X ) );
672
 
 
673
 
  // Show message structure viewer
674
 
  mToggleMimePartTreeAction = new KToggleAction( i18n( "Show Message Structure" ), this );
675
 
  ac->addAction( "toggle_mimeparttree", mToggleMimePartTreeAction );
676
 
  connect( mToggleMimePartTreeAction, SIGNAL(toggled(bool)),
677
 
           SLOT(slotToggleMimePartTree()));
678
 
 
679
 
  //
680
 
  // Scroll actions
681
 
  //
682
 
  mScrollUpAction = new KAction( i18n("Scroll Message Up"), this );
683
 
  mScrollUpAction->setShortcut( QKeySequence( Qt::Key_Up ) );
684
 
  ac->addAction( "scroll_up", mScrollUpAction );
685
 
  connect( mScrollUpAction, SIGNAL( triggered( bool ) ),
686
 
           this, SLOT( slotScrollUp() ) );
687
 
 
688
 
  mScrollDownAction = new KAction( i18n("Scroll Message Down"), this );
689
 
  mScrollDownAction->setShortcut( QKeySequence( Qt::Key_Down ) );
690
 
  ac->addAction( "scroll_down", mScrollDownAction );
691
 
  connect( mScrollDownAction, SIGNAL( triggered( bool ) ),
692
 
           this, SLOT( slotScrollDown() ) );
693
 
 
694
 
  mScrollUpMoreAction = new KAction( i18n("Scroll Message Up (More)"), this );
695
 
  mScrollUpMoreAction->setShortcut( QKeySequence( Qt::Key_PageUp ) );
696
 
  ac->addAction( "scroll_up_more", mScrollUpMoreAction );
697
 
  connect( mScrollUpMoreAction, SIGNAL( triggered( bool ) ),
698
 
           this, SLOT( slotScrollPrior() ) );
699
 
 
700
 
  mScrollDownMoreAction = new KAction( i18n("Scroll Message Down (More)"), this );
701
 
  mScrollDownMoreAction->setShortcut( QKeySequence( Qt::Key_PageDown ) );
702
 
  ac->addAction( "scroll_down_more", mScrollDownMoreAction );
703
 
  connect( mScrollDownMoreAction, SIGNAL( triggered( bool ) ),
704
 
           this, SLOT( slotScrollNext() ) );
705
 
 
706
 
  //
707
 
  // Actions not in menu
708
 
  //
709
 
 
710
 
  // Toggle HTML display mode.
711
 
  mToggleDisplayModeAction = new KToggleAction( i18n( "Toggle HTML Display Mode" ), this );
712
 
  ac->addAction( "toggle_html_display_mode", mToggleDisplayModeAction );
713
 
  connect( mToggleDisplayModeAction, SIGNAL( triggered( bool ) ), SLOT( slotToggleHtmlMode() ) );
714
 
  mToggleDisplayModeAction->setHelpText( i18n( "Toggle display mode between HTML and plain text" ) );
 
192
  // find text
 
193
  KAction *action = new KAction(KIcon("edit-find"), i18n("&Find in Message..."), this);
 
194
  ac->addAction("find_in_messages", action );
 
195
  connect(action, SIGNAL(triggered(bool)), SLOT(slotFind()));
 
196
  action->setShortcut(KStandardShortcut::find());
 
197
 
715
198
}
716
199
 
717
200
void KMReaderWin::setUseFixedFont( bool useFixedFont )
718
201
{
719
 
  mUseFixedFont = useFixedFont;
720
 
  if ( mToggleFixFontAction )
721
 
  {
722
 
    mToggleFixFontAction->setChecked( mUseFixedFont );
723
 
  }
724
 
}
725
 
 
726
 
// little helper function
727
 
KToggleAction *KMReaderWin::actionForHeaderStyle( const HeaderStyle * style, const HeaderStrategy * strategy ) {
728
 
  if ( !mActionCollection )
729
 
    return 0;
730
 
  const char * actionName = 0;
731
 
  if ( style == HeaderStyle::enterprise() )
732
 
    actionName = "view_headers_enterprise";
733
 
  if ( style == HeaderStyle::fancy() )
734
 
    actionName = "view_headers_fancy";
735
 
  else if ( style == HeaderStyle::brief() )
736
 
    actionName = "view_headers_brief";
737
 
  else if ( style == HeaderStyle::plain() ) {
738
 
    if ( strategy == HeaderStrategy::standard() )
739
 
      actionName = "view_headers_standard";
740
 
    else if ( strategy == HeaderStrategy::rich() )
741
 
      actionName = "view_headers_long";
742
 
    else if ( strategy == HeaderStrategy::all() )
743
 
      actionName = "view_headers_all";
744
 
  }
745
 
  if ( actionName )
746
 
    return static_cast<KToggleAction*>(mActionCollection->action(actionName));
747
 
  else
748
 
    return 0;
749
 
}
750
 
 
751
 
KToggleAction *KMReaderWin::actionForAttachmentStrategy( const AttachmentStrategy * as ) {
752
 
  if ( !mActionCollection )
753
 
    return 0;
754
 
  const char * actionName = 0;
755
 
  if ( as == AttachmentStrategy::iconic() )
756
 
    actionName = "view_attachments_as_icons";
757
 
  else if ( as == AttachmentStrategy::smart() )
758
 
    actionName = "view_attachments_smart";
759
 
  else if ( as == AttachmentStrategy::inlined() )
760
 
    actionName = "view_attachments_inline";
761
 
  else if ( as == AttachmentStrategy::hidden() )
762
 
    actionName = "view_attachments_hide";
763
 
 
764
 
  if ( actionName )
765
 
    return static_cast<KToggleAction*>(mActionCollection->action(actionName));
766
 
  else
767
 
    return 0;
768
 
}
769
 
 
770
 
void KMReaderWin::slotEnterpriseHeaders() {
771
 
  setHeaderStyleAndStrategy( HeaderStyle::enterprise(),
772
 
                             HeaderStrategy::rich() );
773
 
  if( !mExternalWindow )
774
 
    writeConfig();
775
 
}
776
 
 
777
 
void KMReaderWin::slotFancyHeaders() {
778
 
  setHeaderStyleAndStrategy( HeaderStyle::fancy(),
779
 
                             HeaderStrategy::rich() );
780
 
  if( !mExternalWindow )
781
 
    writeConfig();
782
 
}
783
 
 
784
 
void KMReaderWin::slotBriefHeaders() {
785
 
  setHeaderStyleAndStrategy( HeaderStyle::brief(),
786
 
                             HeaderStrategy::brief() );
787
 
  if( !mExternalWindow )
788
 
    writeConfig();
789
 
}
790
 
 
791
 
void KMReaderWin::slotStandardHeaders() {
792
 
  setHeaderStyleAndStrategy( HeaderStyle::plain(),
793
 
                             HeaderStrategy::standard());
794
 
  writeConfig();
795
 
}
796
 
 
797
 
void KMReaderWin::slotLongHeaders() {
798
 
  setHeaderStyleAndStrategy( HeaderStyle::plain(),
799
 
                             HeaderStrategy::rich() );
800
 
  if( !mExternalWindow )
801
 
    writeConfig();
802
 
}
803
 
 
804
 
void KMReaderWin::slotAllHeaders() {
805
 
  setHeaderStyleAndStrategy( HeaderStyle::plain(),
806
 
                             HeaderStrategy::all() );
807
 
  if( !mExternalWindow )
808
 
    writeConfig();
809
 
}
810
 
 
811
 
void KMReaderWin::slotLevelQuote( int l )
 
202
  mViewer->setUseFixedFont( useFixedFont );
 
203
}
 
204
 
 
205
bool KMReaderWin::isFixedFont() const
812
206
{
813
 
  mLevelQuote = l;
814
 
  update( true );
815
 
}
816
 
 
817
 
void KMReaderWin::slotCycleHeaderStyles() {
818
 
  const HeaderStrategy * strategy = headerStrategy();
819
 
  const HeaderStyle * style = headerStyle();
820
 
 
821
 
  const char * actionName = 0;
822
 
  if ( style == HeaderStyle::enterprise() ) {
823
 
    slotFancyHeaders();
824
 
    actionName = "view_headers_fancy";
825
 
  }
826
 
  if ( style == HeaderStyle::fancy() ) {
827
 
    slotBriefHeaders();
828
 
    actionName = "view_headers_brief";
829
 
  } else if ( style == HeaderStyle::brief() ) {
830
 
    slotStandardHeaders();
831
 
    actionName = "view_headers_standard";
832
 
  } else if ( style == HeaderStyle::plain() ) {
833
 
    if ( strategy == HeaderStrategy::standard() ) {
834
 
      slotLongHeaders();
835
 
      actionName = "view_headers_long";
836
 
    } else if ( strategy == HeaderStrategy::rich() ) {
837
 
      slotAllHeaders();
838
 
      actionName = "view_headers_all";
839
 
    } else if ( strategy == HeaderStrategy::all() ) {
840
 
      slotEnterpriseHeaders();
841
 
      actionName = "view_headers_enterprise";
842
 
    }
843
 
  }
844
 
 
845
 
  if ( actionName )
846
 
    static_cast<KToggleAction*>( mActionCollection->action( actionName ) )->setChecked( true );
847
 
}
848
 
 
849
 
 
850
 
void KMReaderWin::slotIconicAttachments() {
851
 
  setAttachmentStrategy( AttachmentStrategy::iconic() );
852
 
}
853
 
 
854
 
void KMReaderWin::slotSmartAttachments() {
855
 
  setAttachmentStrategy( AttachmentStrategy::smart() );
856
 
}
857
 
 
858
 
void KMReaderWin::slotInlineAttachments() {
859
 
  setAttachmentStrategy( AttachmentStrategy::inlined() );
860
 
}
861
 
 
862
 
void KMReaderWin::slotHideAttachments() {
863
 
  setAttachmentStrategy( AttachmentStrategy::hidden() );
864
 
}
865
 
 
866
 
void KMReaderWin::slotCycleAttachmentStrategy() {
867
 
  setAttachmentStrategy( attachmentStrategy()->next() );
868
 
  KToggleAction * action = actionForAttachmentStrategy( attachmentStrategy() );
869
 
  assert( action );
870
 
  action->setChecked( true );
871
 
}
872
 
 
 
207
  return mViewer->isFixedFont();
 
208
}
873
209
 
874
210
//-----------------------------------------------------------------------------
875
211
KMReaderWin::~KMReaderWin()
876
212
{
877
 
  clearBodyPartMementos();
878
 
  delete mHtmlWriter; mHtmlWriter = 0;
879
 
  delete mCSSHelper;
880
 
  if (mAutoDelete) delete message();
881
 
  delete mRootNode; mRootNode = 0;
882
 
  removeTempFiles();
883
 
}
884
 
 
885
 
 
886
 
//-----------------------------------------------------------------------------
887
 
void KMReaderWin::slotMessageArrived( KMMessage *msg )
888
 
{
889
 
  if (msg && ((KMMsgBase*)msg)->isMessage()) {
890
 
    if ( msg->getMsgSerNum() == mWaitingForSerNum ) {
891
 
      setMsg( msg, true );
892
 
    } else {
893
 
      kDebug() << "Ignoring update";
894
 
    }
895
 
  }
896
 
}
897
 
 
898
 
//-----------------------------------------------------------------------------
899
 
void KMReaderWin::update( KMail::Interface::Observable * observable )
900
 
{
901
 
  if ( !mAtmUpdate ) {
902
 
    // reparse the msg
903
 
    saveRelativePosition();
904
 
    updateReaderWin();
905
 
    return;
906
 
  }
907
 
 
908
 
  if ( !mRootNode )
909
 
    return;
910
 
 
911
 
  KMMessage* msg = static_cast<KMMessage*>( observable );
912
 
  assert( msg != 0 );
913
 
 
914
 
  // find our partNode and update it
915
 
  if ( !msg->lastUpdatedPart() ) {
916
 
    kDebug() << "No updated part";
917
 
    return;
918
 
  }
919
 
  partNode* node = mRootNode->findNodeForDwPart( msg->lastUpdatedPart() );
920
 
  if ( !node ) {
921
 
    kDebug() << "Can't find node for part";
922
 
    return;
923
 
  }
924
 
  node->setDwPart( msg->lastUpdatedPart() );
925
 
 
926
 
  // update the tmp file
927
 
  // we have to set it writeable temporarily
928
 
  ::chmod( QFile::encodeName( mAtmCurrentName ), S_IRWXU );
929
 
  QByteArray data = node->msgPart().bodyDecodedBinary();
930
 
  if ( node->msgPart().type() == DwMime::kTypeText && data.size() > 0 ) {
931
 
    // convert CRLF to LF before writing text attachments to disk
932
 
    const size_t newsize = KMail::Util::crlf2lf( data.data(), data.size() );
933
 
    data.truncate( newsize );
934
 
  }
935
 
  KPIMUtils::kByteArrayToFile( data, mAtmCurrentName, false, false, false );
936
 
  ::chmod( QFile::encodeName( mAtmCurrentName ), S_IRUSR );
937
 
 
938
 
  mAtmUpdate = false;
939
 
}
940
 
 
941
 
//-----------------------------------------------------------------------------
942
 
void KMReaderWin::removeTempFiles()
943
 
{
944
 
  for (QStringList::Iterator it = mTempFiles.begin(); it != mTempFiles.end();
945
 
    ++it)
946
 
  {
947
 
    QFile::remove(*it);
948
 
  }
949
 
  mTempFiles.clear();
950
 
  for (QStringList::Iterator it = mTempDirs.begin(); it != mTempDirs.end();
951
 
    it++)
952
 
  {
953
 
    QDir(*it).rmdir(*it);
954
 
  }
955
 
  mTempDirs.clear();
956
 
}
957
 
 
958
 
 
959
 
//-----------------------------------------------------------------------------
960
 
bool KMReaderWin::event(QEvent *e)
961
 
{
962
 
  if (e->type() == QEvent::PaletteChange)
963
 
  {
964
 
    delete mCSSHelper;
965
 
    mCSSHelper = new KMail::CSSHelper( mViewer->view() );
966
 
    if (message())
967
 
      message()->readConfig();
968
 
    update( true ); // Force update
969
 
    return true;
970
 
  }
971
 
  return QWidget::event(e);
972
213
}
973
214
 
974
215
 
975
216
//-----------------------------------------------------------------------------
976
217
void KMReaderWin::readConfig(void)
977
218
{
978
 
  delete mCSSHelper;
979
 
  mCSSHelper = new KMail::CSSHelper( mViewer->view() );
980
 
 
981
 
  mNoMDNsWhenEncrypted = GlobalSettings::self()->notSendWhenEncrypted();
982
 
 
983
 
  mUseFixedFont = GlobalSettings::self()->useFixedFont();
984
 
  if ( mToggleFixFontAction )
985
 
    mToggleFixFontAction->setChecked( mUseFixedFont );
986
 
 
987
 
  mHtmlMail = GlobalSettings::self()->htmlMail();
988
 
  mHtmlLoadExternal = GlobalSettings::self()->htmlLoadExternal();
989
 
 
990
 
  KToggleAction *raction = actionForHeaderStyle( headerStyle(), headerStrategy() );
991
 
  if ( raction )
992
 
    raction->setChecked( true );
993
 
 
994
 
  setAttachmentStrategy( AttachmentStrategy::create( GlobalSettings::self()->attachmentStrategy() ) );
995
 
  raction = actionForAttachmentStrategy( attachmentStrategy() );
996
 
  if ( raction )
997
 
    raction->setChecked( true );
998
 
 
999
 
  const int mimeH = GlobalSettings::self()->mimePaneHeight();
1000
 
  const int messageH = GlobalSettings::self()->messagePaneHeight();
1001
 
  mSplitterSizes.clear();
1002
 
  if ( GlobalSettings::self()->mimeTreeLocation() == GlobalSettings::EnumMimeTreeLocation::bottom )
1003
 
    mSplitterSizes << messageH << mimeH;
1004
 
  else
1005
 
    mSplitterSizes << mimeH << messageH;
1006
 
 
1007
 
  adjustLayout();
1008
 
 
1009
 
  readGlobalOverrideCodec();
1010
 
 
1011
 
  // Note that this call triggers an update, see this call has to be at the
1012
 
  // bottom when all settings are already est.
1013
 
  setHeaderStyleAndStrategy( HeaderStyle::create( GlobalSettings::self()->headerStyle() ),
1014
 
                             HeaderStrategy::create( GlobalSettings::self()->headerSetDisplayed() ) );
1015
 
 
1016
 
  if (message())
1017
 
    update();
1018
 
  mColorBar->update();
1019
 
  KMMessage::readConfig();
1020
 
}
1021
 
 
1022
 
 
1023
 
void KMReaderWin::adjustLayout() {
1024
 
  if ( GlobalSettings::self()->mimeTreeLocation() == GlobalSettings::EnumMimeTreeLocation::bottom )
1025
 
    mSplitter->addWidget( mMimePartTree );
1026
 
  else
1027
 
    mSplitter->insertWidget( 0, mMimePartTree );
1028
 
  mSplitter->setSizes( mSplitterSizes );
1029
 
 
1030
 
  if ( GlobalSettings::self()->mimeTreeMode() == GlobalSettings::EnumMimeTreeMode::Always &&
1031
 
       mMsgDisplay )
1032
 
    mMimePartTree->show();
1033
 
  else
1034
 
    mMimePartTree->hide();
1035
 
 
1036
 
  if ( GlobalSettings::self()->showColorbar() && mMsgDisplay )
1037
 
    mColorBar->show();
1038
 
  else
1039
 
    mColorBar->hide();
1040
 
}
1041
 
 
1042
 
 
1043
 
void KMReaderWin::saveSplitterSizes() const {
1044
 
  if ( !mSplitter || !mMimePartTree )
1045
 
    return;
1046
 
  if ( mMimePartTree->isHidden() )
1047
 
    return; // don't rely on QSplitter maintaining sizes for hidden widgets.
1048
 
 
1049
 
  const bool mimeTreeAtBottom = GlobalSettings::self()->mimeTreeLocation() == GlobalSettings::EnumMimeTreeLocation::bottom;
1050
 
  GlobalSettings::self()->setMimePaneHeight( mSplitter->sizes()[ mimeTreeAtBottom ? 1 : 0 ] );
1051
 
  GlobalSettings::self()->setMessagePaneHeight( mSplitter->sizes()[ mimeTreeAtBottom ? 0 : 1 ] );
1052
 
}
1053
 
 
1054
 
//-----------------------------------------------------------------------------
1055
 
void KMReaderWin::writeConfig( bool sync ) const {
1056
 
  GlobalSettings::self()->setUseFixedFont( mUseFixedFont );
1057
 
  if ( headerStyle() )
1058
 
    GlobalSettings::self()->setHeaderStyle( headerStyle()->name() );
1059
 
  if ( headerStrategy() )
1060
 
    GlobalSettings::self()->setHeaderSetDisplayed( headerStrategy()->name() );
1061
 
  if ( attachmentStrategy() )
1062
 
    GlobalSettings::self()->setAttachmentStrategy( attachmentStrategy()->name() );
1063
 
 
1064
 
  saveSplitterSizes();
1065
 
 
1066
 
  if ( sync )
1067
 
    kmkernel->slotRequestConfigSync();
1068
 
}
1069
 
 
1070
 
//-----------------------------------------------------------------------------
1071
 
void KMReaderWin::initHtmlWidget(void)
1072
 
{
1073
 
  mViewer->widget()->setFocusPolicy(Qt::WheelFocus);
1074
 
  // Let's better be paranoid and disable plugins (it defaults to enabled):
1075
 
  mViewer->setPluginsEnabled(false);
1076
 
  mViewer->setJScriptEnabled(false); // just make this explicit
1077
 
  mViewer->setJavaEnabled(false);    // just make this explicit
1078
 
  mViewer->setMetaRefreshEnabled(false);
1079
 
  mViewer->setURLCursor( QCursor( Qt::PointingHandCursor ) );
1080
 
  // Espen 2000-05-14: Getting rid of thick ugly frames
1081
 
  mViewer->view()->setLineWidth(0);
1082
 
  // register our own event filter for shift-click
1083
 
  mViewer->view()->widget()->installEventFilter( this );
1084
 
 
1085
 
  if ( !htmlWriter() ) {
1086
 
    mPartHtmlWriter = new KHtmlPartHtmlWriter( mViewer, 0 );
1087
 
#ifdef KMAIL_READER_HTML_DEBUG
1088
 
    mHtmlWriter = new TeeHtmlWriter( new FileHtmlWriter( QString() ),
1089
 
                                     mPartHtmlWriter );
1090
 
#else
1091
 
    mHtmlWriter = mPartHtmlWriter;
1092
 
#endif
1093
 
  }
1094
 
 
1095
 
  // We do a queued connection below, and for that we need to register the meta types of the
1096
 
  // parameters.
1097
 
  //
1098
 
  // Why do we do a queued connection instead of a direct one? slotUrlOpen() handles those clicks,
1099
 
  // and can end up in the click handler for accepting invitations. That handler can pop up a dialog
1100
 
  // asking the user for a comment on the invitation reply. This dialog is started with exec(), i.e.
1101
 
  // executes a sub-eventloop. This sub-eventloop then eventually re-enters the KHTML event handler,
1102
 
  // which then thinks we started a drag, and therefore adds a silly drag object to the cursor, with
1103
 
  // urls like x-kmail-whatever/43/8/accept, and we don't want that drag object.
1104
 
  //
1105
 
  // Therefore, use queued connections to avoid the reentry of the KHTML event loop, so we don't
1106
 
  // get the drag object.
1107
 
  static bool metaTypesRegistered = false;
1108
 
  if ( !metaTypesRegistered ) {
1109
 
    qRegisterMetaType<KParts::OpenUrlArguments>( "KParts::OpenUrlArguments" );
1110
 
    qRegisterMetaType<KParts::BrowserArguments>( "KParts::BrowserArguments" );
1111
 
    qRegisterMetaType<KParts::WindowArgs>( "KParts::WindowArgs" );
1112
 
    metaTypesRegistered = true;
1113
 
  }
1114
 
 
1115
 
  connect(mViewer->browserExtension(),
1116
 
          SIGNAL(openUrlRequest(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),this,
1117
 
          SLOT(slotUrlOpen(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),
1118
 
          Qt::QueuedConnection);
1119
 
  connect(mViewer->browserExtension(),
1120
 
          SIGNAL(createNewWindow(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),this,
1121
 
          SLOT(slotUrlOpen(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),
1122
 
          Qt::QueuedConnection);
1123
 
  connect(mViewer,SIGNAL(onURL(const QString &)),this,
1124
 
          SLOT(slotUrlOn(const QString &)));
1125
 
  connect(mViewer,SIGNAL(popupMenu(const QString &, const QPoint &)),
1126
 
          SLOT(slotUrlPopup(const QString &, const QPoint &)));
 
219
  mViewer->readConfig();
1127
220
}
1128
221
 
1129
222
void KMReaderWin::setAttachmentStrategy( const AttachmentStrategy * strategy ) {
1130
 
  mAttachmentStrategy = strategy ? strategy : AttachmentStrategy::smart();
1131
 
  update( true );
 
223
  mViewer->setAttachmentStrategy( strategy );
1132
224
}
1133
225
 
1134
 
void KMReaderWin::setHeaderStyleAndStrategy( const HeaderStyle * style,
 
226
void KMReaderWin::setHeaderStyleAndStrategy( HeaderStyle * style,
1135
227
                                             const HeaderStrategy * strategy ) {
1136
 
  mHeaderStyle = style ? style : HeaderStyle::fancy();
1137
 
  mHeaderStrategy = strategy ? strategy : HeaderStrategy::rich();
1138
 
  update( true );
 
228
  mViewer->setHeaderStyleAndStrategy( style, strategy );
1139
229
}
1140
 
 
1141
230
//-----------------------------------------------------------------------------
1142
231
void KMReaderWin::setOverrideEncoding( const QString & encoding )
1143
232
{
1144
 
  if ( encoding == mOverrideEncoding )
1145
 
    return;
1146
 
 
1147
 
  mOverrideEncoding = encoding;
1148
 
  if ( mSelectEncodingAction ) {
1149
 
    if ( encoding.isEmpty() ) {
1150
 
      mSelectEncodingAction->setCurrentItem( 0 );
1151
 
    }
1152
 
    else {
1153
 
      QStringList encodings = mSelectEncodingAction->items();
1154
 
      int i = 0;
1155
 
      for ( QStringList::const_iterator it = encodings.constBegin(), end = encodings.constEnd(); it != end; ++it, ++i ) {
1156
 
        if ( KMMsgBase::encodingForName( *it ) == encoding ) {
1157
 
          mSelectEncodingAction->setCurrentItem( i );
1158
 
          break;
1159
 
        }
1160
 
      }
1161
 
      if ( i == encodings.size() ) {
1162
 
        // the value of encoding is unknown => use Auto
1163
 
        kWarning() <<"Unknown override character encoding \"" << encoding
1164
 
                       << "\". Using Auto instead.";
1165
 
        mSelectEncodingAction->setCurrentItem( 0 );
1166
 
        mOverrideEncoding.clear();
1167
 
      }
1168
 
    }
1169
 
  }
1170
 
  update( true );
1171
 
}
1172
 
 
1173
 
//-----------------------------------------------------------------------------
1174
 
const QTextCodec * KMReaderWin::overrideCodec() const
1175
 
{
1176
 
  if ( mOverrideEncoding.isEmpty() || mOverrideEncoding == "Auto" ) // Auto
1177
 
    return 0;
1178
 
  else
1179
 
    return KMMsgBase::codecForName( mOverrideEncoding.toLatin1() );
1180
 
}
1181
 
 
1182
 
//-----------------------------------------------------------------------------
1183
 
void KMReaderWin::slotSetEncoding()
1184
 
{
1185
 
  if ( mSelectEncodingAction->currentItem() == 0 ) // Auto
1186
 
    mOverrideEncoding.clear();
1187
 
  else
1188
 
    mOverrideEncoding = KMMsgBase::encodingForName( mSelectEncodingAction->currentText() );
1189
 
  update( true );
1190
 
}
1191
 
 
1192
 
//-----------------------------------------------------------------------------
1193
 
void KMReaderWin::readGlobalOverrideCodec()
1194
 
{
1195
 
  // if the global character encoding wasn't changed then there's nothing to do
1196
 
  if ( GlobalSettings::self()->overrideCharacterEncoding() == mOldGlobalOverrideEncoding )
1197
 
    return;
1198
 
 
1199
 
  setOverrideEncoding( GlobalSettings::self()->overrideCharacterEncoding() );
1200
 
  mOldGlobalOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding();
1201
 
}
1202
 
 
1203
 
//-----------------------------------------------------------------------------
1204
 
void KMReaderWin::setOriginalMsg( unsigned long serNumOfOriginalMessage, int nodeIdOffset )
1205
 
{
1206
 
  mSerNumOfOriginalMessage = serNumOfOriginalMessage;
1207
 
  mNodeIdOffset = nodeIdOffset;
1208
 
}
1209
 
 
1210
 
//-----------------------------------------------------------------------------
1211
 
void KMReaderWin::setMsg( KMMessage* aMsg, bool force )
1212
 
{
1213
 
  if ( aMsg ) {
1214
 
    kDebug() << "(" << aMsg->getMsgSerNum() <<", last" << mLastSerNum <<")" << aMsg->subject()
1215
 
             << aMsg->fromStrip() << ", readyToShow" << (aMsg->readyToShow());
1216
 
  }
1217
 
 
1218
 
  // Reset message-transient state
1219
 
  if (aMsg && aMsg->getMsgSerNum() != mLastSerNum ){
1220
 
    mLevelQuote = GlobalSettings::self()->collapseQuoteLevelSpin()-1;
1221
 
    clearBodyPartMementos();
1222
 
  }
1223
 
  if ( mPrinting )
1224
 
    mLevelQuote = -1;
1225
 
 
1226
 
  bool complete = true;
1227
 
  if ( aMsg &&
1228
 
       !aMsg->readyToShow() &&
1229
 
       (aMsg->getMsgSerNum() != mLastSerNum) &&
1230
 
       !aMsg->isComplete() )
1231
 
    complete = false;
1232
 
 
1233
 
  // If not forced and there is aMsg and aMsg is same as mMsg then return
1234
 
  if (!force && aMsg && mLastSerNum != 0 && aMsg->getMsgSerNum() == mLastSerNum)
1235
 
    return;
1236
 
 
1237
 
  // (de)register as observer
1238
 
  if (aMsg && message())
1239
 
    message()->detach( this );
1240
 
  if (aMsg)
1241
 
    aMsg->attach( this );
1242
 
  mAtmUpdate = false;
1243
 
 
1244
 
  // connect to the updates if we have hancy headers
1245
 
 
1246
 
  mDelayedMarkTimer.stop();
1247
 
 
1248
 
  mMessage = 0;
1249
 
  if ( !aMsg ) {
1250
 
    mWaitingForSerNum = 0; // otherwise it has been set
1251
 
    mLastSerNum = 0;
1252
 
  } else {
1253
 
    mLastSerNum = aMsg->getMsgSerNum();
1254
 
    // Check if the serial number can be used to find the assoc KMMessage
1255
 
    // If so, keep only the serial number (and not mMessage), to avoid a dangling mMessage
1256
 
    // when going to another message in the mainwindow.
1257
 
    // Otherwise, keep only mMessage, this is fine for standalone KMReaderMainWins since
1258
 
    // we're working on a copy of the KMMessage, which we own.
1259
 
    if (message() != aMsg) {
1260
 
      mMessage = aMsg;
1261
 
      mLastSerNum = 0;
1262
 
    }
1263
 
  }
1264
 
 
1265
 
  if (aMsg) {
1266
 
    aMsg->setOverrideCodec( overrideCodec() );
1267
 
    aMsg->setDecodeHTML( htmlMail() );
1268
 
    // FIXME: workaround to disable DND for IMAP load-on-demand
1269
 
    if ( !aMsg->isComplete() )
1270
 
      mViewer->setDNDEnabled( false );
1271
 
    else
1272
 
      mViewer->setDNDEnabled( true );
1273
 
  }
1274
 
 
1275
 
  // only display the msg if it is complete
1276
 
  // otherwise we'll get flickering with progressively loaded messages
1277
 
  if ( complete )
1278
 
  {
1279
 
    // Avoid flicker, somewhat of a cludge
1280
 
    if (force) {
1281
 
      // stop the timer to avoid calling updateReaderWin twice
1282
 
      mUpdateReaderWinTimer.stop();
1283
 
      updateReaderWin();
1284
 
    }
1285
 
    else if (mUpdateReaderWinTimer.isActive()) {
1286
 
      mUpdateReaderWinTimer.setInterval( delay );
1287
 
    } else {
1288
 
      mUpdateReaderWinTimer.start( 0 );
1289
 
    }
1290
 
  }
1291
 
 
1292
 
  if ( aMsg && (aMsg->status().isUnread() || aMsg->status().isNew())
1293
 
       && GlobalSettings::self()->delayedMarkAsRead() ) {
1294
 
    if ( GlobalSettings::self()->delayedMarkTime() != 0 )
1295
 
      mDelayedMarkTimer.start( GlobalSettings::self()->delayedMarkTime() * 1000 );
1296
 
    else
1297
 
      slotTouchMessage();
1298
 
  }
 
233
  mViewer->setOverrideEncoding( encoding );
1299
234
}
1300
235
 
1301
236
//-----------------------------------------------------------------------------
1302
237
void KMReaderWin::clearCache()
1303
238
{
1304
 
  mUpdateReaderWinTimer.stop();
1305
239
  clear();
1306
 
  mDelayedMarkTimer.stop();
1307
 
  mLastSerNum = 0;
1308
 
  mWaitingForSerNum = 0;
1309
 
  mMessage = 0;
1310
240
}
1311
241
 
1312
242
// enter items for the "Important changes" list here:
1313
243
static const char * const kmailChanges[] = {
1314
 
  ""
 
244
  I18N_NOOP( "KMail is now based on the Akonadi Personal Information Management framework, which brings many "
 
245
  "changes all around.")
1315
246
};
1316
247
static const int numKMailChanges =
1317
248
  sizeof kmailChanges / sizeof *kmailChanges;
1321
252
// the translators). Note that the <li>...</li> tags are added
1322
253
// automatically below:
1323
254
static const char * const kmailNewFeatures[] = {
1324
 
  ""
 
255
  I18N_NOOP( "Push email (IMAP IDLE)" ),
 
256
  I18N_NOOP( "Improved virtual folders" ),
 
257
  I18N_NOOP( "Improved searches" ),
 
258
  I18N_NOOP( "Support for adding notes (annotations) to mails" ),
 
259
  I18N_NOOP( "Tag folders" ),
 
260
  I18N_NOOP( "Less GUI freezes, mail checks happen in the background" )
1325
261
};
1326
262
static const int numKMailNewFeatures =
1327
263
  sizeof kmailNewFeatures / sizeof *kmailNewFeatures;
1343
279
//-----------------------------------------------------------------------------
1344
280
void KMReaderWin::displaySplashPage( const QString &info )
1345
281
{
1346
 
  mMsgDisplay = false;
1347
 
  adjustLayout();
1348
 
 
1349
 
  QString location = KStandardDirs::locate("data", "kmail/about/main.html");
1350
 
  QString content = KPIMUtils::kFileToByteArray( location );
1351
 
  content = content.arg( KStandardDirs::locate( "data", "kdeui/about/kde_infopage.css" ) );
1352
 
  if ( QApplication::isRightToLeft() )
1353
 
    content = content.arg( "@import \"" + KStandardDirs::locate( "data",
1354
 
                           "kdeui/about/kde_infopage_rtl.css" ) +  "\";");
1355
 
  else
1356
 
    content = content.arg( "" );
1357
 
 
1358
 
  mViewer->begin(KUrl::fromPath( location ));
1359
 
 
1360
 
  QString fontSize = QString::number( pointsToPixel( mCSSHelper->bodyFont().pointSize() ) );
1361
 
  QString appTitle = i18n("KMail");
1362
 
  QString catchPhrase = ""; //not enough space for a catch phrase at default window size i18n("Part of the Kontact Suite");
1363
 
  QString quickDescription = i18n("The email client for the K Desktop Environment.");
1364
 
  mViewer->write(content.arg(fontSize).arg(appTitle).arg(catchPhrase).arg(quickDescription).arg(info));
1365
 
  mViewer->end();
 
282
  mViewer->displaySplashPage( info );
1366
283
}
1367
284
 
1368
285
void KMReaderWin::displayBusyPage()
1387
304
void KMReaderWin::displayAboutPage()
1388
305
{
1389
306
  KLocalizedString info =
1390
 
    ki18nc("%1: KMail version; %2: help:// URL; %3: homepage URL; "
1391
 
         "%4: generated list of new features; "
1392
 
         "%5: First-time user text (only shown on first start); "
1393
 
         "%6: generated list of important changes; "
 
307
    ki18nc("%1: KMail version; %2: help:// URL; "
 
308
         "%3: generated list of new features; "
 
309
         "%4: First-time user text (only shown on first start); "
 
310
         "%5: generated list of important changes; "
1394
311
         "--- end of comment ---",
1395
 
         "<h2 style='margin-top: 0px;'>Welcome to KMail %1</h2><p>KMail is the email client for the K "
1396
 
         "Desktop Environment. It is designed to be fully compatible with "
1397
 
         "Internet mailing standards including MIME, SMTP, POP3 and IMAP."
 
312
         "<h2 style='margin-top: 0px;'>Welcome to KMail %1</h2><p>KMail is the email client by KDE."
 
313
         "It is designed to be fully compatible with "
 
314
         "Internet mailing standards including MIME, SMTP, POP3, and IMAP."
1398
315
         "</p>\n"
1399
316
         "<ul><li>KMail has many powerful features which are described in the "
1400
317
         "<a href=\"%2\">documentation</a></li>\n"
1401
 
         "<li>The <a href=\"%3\">KMail homepage</A> offers information about "
1402
 
         "new versions of KMail</li></ul>\n"
1403
 
         "%6\n" // important changes
1404
 
         "%4\n" // new features
1405
 
         "%5\n" // first start info
 
318
         "%5\n" // important changes
 
319
         "%3\n" // new features
 
320
         "%4\n" // first start info
1406
321
         "<p>We hope that you will enjoy KMail.</p>\n"
1407
322
         "<p>Thank you,</p>\n"
1408
323
         "<p style='margin-bottom: 0px'>&nbsp; &nbsp; The KMail Team</p>")
1409
 
           .subs( KMAIL_VERSION ) // KMail version
1410
 
           .subs( "help:/kmail/index.html" ) // KMail help:// URL
1411
 
           .subs( "http://kontact.kde.org/kmail/" ); // KMail homepage URL
 
324
           .subs( KDEPIM_VERSION )
 
325
           .subs( "help:/kmail/index.html" );
1412
326
 
1413
327
  if ( ( numKMailNewFeatures > 1 ) || ( numKMailNewFeatures == 1 && strlen(kmailNewFeatures[0]) > 0 ) ) {
1414
328
    QString featuresText =
1415
329
      i18n("<p>Some of the new features in this release of KMail include "
1416
 
           "(compared to KMail %1, which is part of KDE %2):</p>\n",
1417
 
       QString("1.9"), QString("3.5")); // prior KMail and KDE version
 
330
           "(compared to KMail %1, which is part of KDE Software Compilation %2):</p>\n",
 
331
           QString("1.13"), KDE::versionString() ); // prior KMail and KDE version
1418
332
    featuresText += "<ul>\n";
1419
 
    for ( int i = 0 ; i < numKMailChanges ; i++ )
 
333
    for ( int i = 0 ; i < numKMailNewFeatures ; i++ )
1420
334
      featuresText += "<li>" + i18n( kmailNewFeatures[i] ) + "</li>\n";
1421
335
    featuresText += "</ul>\n";
1422
336
    info = info.subs( featuresText );
1439
353
    QString changesText =
1440
354
      i18n("<p><span style='font-size:125%; font-weight:bold;'>"
1441
355
           "Important changes</span> (compared to KMail %1):</p>\n",
1442
 
       QString("1.9"));
 
356
       QString("1.13"));
1443
357
    changesText += "<ul>\n";
1444
358
    for ( int i = 0 ; i < numKMailChanges ; i++ )
1445
359
      changesText += i18n("<li>%1</li>\n", i18n( kmailChanges[i] ) );
1452
366
  displaySplashPage( info.toString() );
1453
367
}
1454
368
 
1455
 
void KMReaderWin::enableMsgDisplay() {
1456
 
  mMsgDisplay = true;
1457
 
  adjustLayout();
1458
 
}
1459
 
 
1460
 
 
1461
 
//-----------------------------------------------------------------------------
1462
 
 
1463
 
void KMReaderWin::updateReaderWin()
1464
 
{
1465
 
  if ( !mMsgDisplay ) {
1466
 
    return;
1467
 
  }
1468
 
 
1469
 
  mViewer->setOnlyLocalReferences( !htmlLoadExternal() );
1470
 
 
1471
 
  htmlWriter()->reset();
1472
 
 
1473
 
  if ( message() ) {
1474
 
    if ( GlobalSettings::self()->showColorbar() ) {
1475
 
      mColorBar->show();
1476
 
    } else {
1477
 
      mColorBar->hide();
1478
 
    }
1479
 
    displayMessage();
1480
 
  } else {
1481
 
    mColorBar->hide();
1482
 
    mMimePartTree->hide();
1483
 
    mMimePartTree->clearAndResetSortOrder();
1484
 
    htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
1485
 
    htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) + "</body></html>" );
1486
 
    htmlWriter()->end();
1487
 
  }
1488
 
 
1489
 
  if ( mSavedRelativePosition ) {
1490
 
    QScrollBar *scrollBar = mViewer->view()->verticalScrollBar();
1491
 
    scrollBar->setValue( scrollBar->maximum() * mSavedRelativePosition );
1492
 
    mSavedRelativePosition = 0;
1493
 
  }
1494
 
}
1495
 
 
1496
 
//-----------------------------------------------------------------------------
1497
 
int KMReaderWin::pointsToPixel(int pointSize) const
1498
 
{
1499
 
  return (pointSize * mViewer->view()->logicalDpiY() + 36) / 72;
1500
 
}
1501
 
 
1502
 
//-----------------------------------------------------------------------------
1503
 
void KMReaderWin::showHideMimeTree() {
1504
 
  if ( GlobalSettings::self()->mimeTreeMode() == GlobalSettings::EnumMimeTreeMode::Always )
1505
 
    mMimePartTree->show();
1506
 
  else {
1507
 
    // don't rely on QSplitter maintaining sizes for hidden widgets:
1508
 
    saveSplitterSizes();
1509
 
    mMimePartTree->hide();
1510
 
  }
1511
 
  if ( mToggleMimePartTreeAction && ( mToggleMimePartTreeAction->isChecked() != mMimePartTree->isVisible() ) )
1512
 
    mToggleMimePartTreeAction->setChecked( mMimePartTree->isVisible() );
1513
 
}
1514
 
 
1515
 
void KMReaderWin::displayMessage() {
1516
 
  KMMessage * msg = message();
1517
 
 
1518
 
  mMimePartTree->clearAndResetSortOrder();
1519
 
  showHideMimeTree();
1520
 
 
1521
 
  if ( !msg )
1522
 
    return;
1523
 
 
1524
 
  msg->setOverrideCodec( overrideCodec() );
1525
 
 
1526
 
  htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
1527
 
  htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
1528
 
 
1529
 
  if (!parent())
1530
 
    setWindowTitle(msg->subject());
1531
 
 
1532
 
  removeTempFiles();
1533
 
 
1534
 
  mColorBar->setNormalMode();
1535
 
 
1536
 
  parseMsg(msg);
1537
 
 
1538
 
  htmlWriter()->queue("</body></html>");
1539
 
  htmlWriter()->flush();
1540
 
 
1541
 
  // For some reason the DOM is not complete at this moment.
1542
 
  // But if the below functions are called using a singleShot timer
1543
 
  // everything just seems to work.
1544
 
  QTimer::singleShot( 1, this, SLOT( toggleFullAddressList() ) );
1545
 
  QTimer::singleShot( 1, this, SLOT(injectAttachments()) );
1546
 
}
1547
 
 
1548
 
static bool message_was_saved_decrypted_before( const KMMessage * msg )
1549
 
{
1550
 
  if ( !msg )
1551
 
    return false;
1552
 
  kDebug() << "msgId =" << msg->msgId();
1553
 
  return msg->msgId().trimmed().startsWith( "<DecryptedMsg." );
1554
 
}
1555
 
 
1556
 
//-----------------------------------------------------------------------------
1557
 
void KMReaderWin::parseMsg(KMMessage* aMsg)
1558
 
{
1559
 
  KMMessagePart msgPart;
1560
 
 
1561
 
  assert(aMsg!=0);
1562
 
 
1563
 
  aMsg->setIsBeingParsed( true );
1564
 
 
1565
 
  if ( mRootNode && !mRootNode->processed() ) {
1566
 
    kWarning() << "The root node is not yet processed! Danger!";
1567
 
    return;
1568
 
  } else {
1569
 
    delete mRootNode;
1570
 
  }
1571
 
  mRootNode = partNode::fromMessage( aMsg, this );
1572
 
  const QByteArray mainCntTypeStr = mRootNode->typeString() + '/' + mRootNode->subTypeString();
1573
 
 
1574
 
  QString cntDesc = aMsg->subject();
1575
 
  if( cntDesc.isEmpty() )
1576
 
    cntDesc = i18n("( body part )");
1577
 
  KIO::filesize_t cntSize = aMsg->msgSize();
1578
 
  QString cntEnc;
1579
 
  if( aMsg->contentTransferEncodingStr().isEmpty() )
1580
 
    cntEnc = "7bit";
1581
 
  else
1582
 
    cntEnc = aMsg->contentTransferEncodingStr();
1583
 
 
1584
 
  // fill the MIME part tree viewer
1585
 
  mRootNode->fillMimePartTree( 0, mMimePartTree, cntDesc, mainCntTypeStr,
1586
 
                               cntEnc, cntSize );
1587
 
 
1588
 
  // Check if any part of this message is a v-card
1589
 
  // v-cards can be either text/x-vcard or text/directory, so we need to check
1590
 
  // both.
1591
 
  partNode* vCardNode = mRootNode->findType( DwMime::kTypeText, DwMime::kSubtypeXVCard );
1592
 
  if ( !vCardNode )
1593
 
    vCardNode = mRootNode->findType( DwMime::kTypeText, DwMime::kSubtypeDirectory );
1594
 
 
1595
 
  bool hasVCard = false;
1596
 
  if( vCardNode ) {
1597
 
    // ### FIXME: We should only do this if the vCard belongs to the sender,
1598
 
    // ### i.e. if the sender's email address is contained in the vCard.
1599
 
    const QByteArray vCard = vCardNode->msgPart().bodyDecodedBinary();
1600
 
    KABC::VCardConverter t;
1601
 
    if ( !t.parseVCards( vCard ).isEmpty() ) {
1602
 
      hasVCard = true;
1603
 
      kDebug() << "FOUND A VALID VCARD";
1604
 
      writeMessagePartToTempFile( &vCardNode->msgPart(), vCardNode->nodeId() );
1605
 
    }
1606
 
  }
1607
 
  htmlWriter()->queue( writeMsgHeader(aMsg, hasVCard ? vCardNode : 0, true ) );
1608
 
 
1609
 
  // show message content
1610
 
  ObjectTreeParser otp( this );
1611
 
  otp.setAllowAsync( true );
1612
 
  otp.parseObjectTree( mRootNode );
1613
 
 
1614
 
  // store encrypted/signed status information in the KMMessage
1615
 
  //  - this can only be done *after* calling parseObjectTree()
1616
 
  KMMsgEncryptionState encryptionState = mRootNode->overallEncryptionState();
1617
 
  KMMsgSignatureState  signatureState  = mRootNode->overallSignatureState();
1618
 
  // Don't crash when switching message while GPG passphrase entry dialog is shown #53185
1619
 
  if (aMsg != message()) {
1620
 
    displayMessage();
1621
 
    return;
1622
 
  }
1623
 
  aMsg->setEncryptionState( encryptionState );
1624
 
  // Don't reset the signature state to "not signed" (e.g. if one canceled the
1625
 
  // decryption of a signed messages which has already been decrypted before).
1626
 
  if ( signatureState != KMMsgNotSigned ||
1627
 
       aMsg->signatureState() == KMMsgSignatureStateUnknown ) {
1628
 
    aMsg->setSignatureState( signatureState );
1629
 
  }
1630
 
 
1631
 
  bool emitReplaceMsgByUnencryptedVersion = false;
1632
 
  const KConfigGroup reader( KMKernel::config(), "Reader" );
1633
 
  if ( reader.readEntry( "store-displayed-messages-unencrypted", false ) ) {
1634
 
 
1635
 
    // Hack to make sure the S/MIME CryptPlugs follows the strict requirement
1636
 
    // of german government:
1637
 
    // --> All received encrypted messages *must* be stored in unencrypted form
1638
 
    //     after they have been decrypted once the user has read them.
1639
 
    //     ( "Aufhebung der Verschluesselung nach dem Lesen" )
1640
 
    //
1641
 
    // note: Since there is no configuration option for this, we do that for
1642
 
    //       all kinds of encryption now - *not* just for S/MIME.
1643
 
    //       This could be changed in the objectTreeToDecryptedMsg() function
1644
 
    //       by deciding when (or when not, resp.) to set the 'dataNode' to
1645
 
    //       something different than 'curNode'.
1646
 
 
1647
 
 
1648
 
    kDebug() << "\n\n\nSpecial post-encryption handling:\n1.";
1649
 
    kDebug() << "(aMsg == msg) ="                      << (aMsg == message());
1650
 
    kDebug() << "aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() = " << (aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder());
1651
 
    kDebug() << "message_was_saved_decrypted_before( aMsg ) = " << message_was_saved_decrypted_before( aMsg );
1652
 
    kDebug() << "this->decryptMessage() = " << decryptMessage();
1653
 
    kDebug() << "otp.hasPendingAsyncJobs() = " << otp.hasPendingAsyncJobs();
1654
 
    kDebug() << "   (KMMsgFullyEncrypted == encryptionState) = "     << (KMMsgFullyEncrypted == encryptionState);
1655
 
    kDebug() <<"|| (KMMsgPartiallyEncrypted == encryptionState) =" << (KMMsgPartiallyEncrypted == encryptionState);
1656
 
         // only proceed if we were called the normal way - not by
1657
 
         // double click on the message (==not running in a separate window)
1658
 
    if(    (aMsg == message())
1659
 
          // don't remove encryption in the outbox folder :)
1660
 
        && ( aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() )
1661
 
          // only proceed if this message was not saved encryptedly before
1662
 
        && !message_was_saved_decrypted_before( aMsg )
1663
 
          // only proceed if the message has actually been decrypted
1664
 
        && decryptMessage()
1665
 
          // only proceed if no pending async jobs are running:
1666
 
        && !otp.hasPendingAsyncJobs()
1667
 
          // only proceed if this message is (at least partially) encrypted
1668
 
        && (    (KMMsgFullyEncrypted == encryptionState)
1669
 
            || (KMMsgPartiallyEncrypted == encryptionState) ) ) {
1670
 
 
1671
 
      kDebug() << "Calling objectTreeToDecryptedMsg()";
1672
 
 
1673
 
      QByteArray decryptedData;
1674
 
      // note: The following call may change the message's headers.
1675
 
      objectTreeToDecryptedMsg( mRootNode, decryptedData, *aMsg );
1676
 
      kDebug() << "Resulting data:" << decryptedData;
1677
 
 
1678
 
      if( !decryptedData.isEmpty() ) {
1679
 
        kDebug() << "Composing unencrypted message";
1680
 
        // try this:
1681
 
        aMsg->setBody( decryptedData );
1682
 
        KMMessage* unencryptedMessage = new KMMessage( *aMsg );
1683
 
        unencryptedMessage->setParent( 0 );
1684
 
        // because this did not work:
1685
 
        /*
1686
 
        DwMessage dwMsg( DwString( aMsg->asString() ) );
1687
 
        dwMsg.Body() = DwBody( DwString( resultString.data() ) );
1688
 
        dwMsg.Body().Parse();
1689
 
        KMMessage* unencryptedMessage = new KMMessage( &dwMsg );
1690
 
        */
1691
 
        kDebug() << "Resulting message:" << unencryptedMessage->asString();
1692
 
        kDebug() << "Attach unencrypted message to aMsg";
1693
 
        aMsg->setUnencryptedMsg( unencryptedMessage );
1694
 
        emitReplaceMsgByUnencryptedVersion = true;
1695
 
      }
1696
 
    }
1697
 
  }
1698
 
 
1699
 
  // store message id to avoid endless recursions
1700
 
  setIdOfLastViewedMessage( aMsg->msgId() );
1701
 
 
1702
 
  if( emitReplaceMsgByUnencryptedVersion ) {
1703
 
    kDebug() << "Invoce saving in decrypted form:";
1704
 
    emit replaceMsgByUnencryptedVersion();
1705
 
  } else {
1706
 
    showHideMimeTree();
1707
 
  }
1708
 
 
1709
 
  aMsg->setIsBeingParsed( false );
1710
 
}
1711
 
 
1712
 
 
1713
 
//-----------------------------------------------------------------------------
1714
 
QString KMReaderWin::writeMsgHeader( KMMessage* aMsg, partNode *vCardNode, bool topLevel )
1715
 
{
1716
 
  if ( !headerStyle() ) {
1717
 
    kFatal() << "Trying to writeMsgHeader() without a header style set!";
1718
 
  }
1719
 
  if ( !headerStrategy() ) {
1720
 
    kFatal() << "trying to writeMsgHeader() without a header strategy set!";
1721
 
  }
1722
 
  QString href;
1723
 
  if ( vCardNode )
1724
 
    href = vCardNode->asHREF( "body" );
1725
 
 
1726
 
  return headerStyle()->format( aMsg, headerStrategy(), href, mPrinting, topLevel );
1727
 
}
1728
 
 
1729
 
//-----------------------------------------------------------------------------
1730
 
QString KMReaderWin::writeMessagePartToTempFile( KMMessagePart* aMsgPart,
1731
 
                                                 int aPartNum )
1732
 
{
1733
 
  // If the message part is already written to a file, no point in doing it again.
1734
 
  // This function is called twice actually, once from the rendering of the attachment
1735
 
  // in the body and once for the header.
1736
 
  const partNode * node = mRootNode->findId( aPartNum );
1737
 
  KUrl existingFileName = tempFileUrlFromPartNode( node );
1738
 
  if ( !existingFileName.isEmpty() ) {
1739
 
    return existingFileName.toLocalFile();
1740
 
  }
1741
 
 
1742
 
  QString fileName = aMsgPart->fileName();
1743
 
  if( fileName.isEmpty() )
1744
 
    fileName = aMsgPart->name();
1745
 
 
1746
 
  QString fname = createTempDir( QString::number( aPartNum ) );
1747
 
  if ( fname.isEmpty() )
1748
 
    return QString();
1749
 
 
1750
 
  // strip off a leading path
1751
 
  int slashPos = fileName.lastIndexOf( '/' );
1752
 
  if( -1 != slashPos )
1753
 
    fileName = fileName.mid( slashPos + 1 );
1754
 
  if( fileName.isEmpty() )
1755
 
    fileName = "unnamed";
1756
 
  fname += '/' + fileName;
1757
 
 
1758
 
  QByteArray data = aMsgPart->bodyDecodedBinary();
1759
 
  if ( aMsgPart->type() == DwMime::kTypeText && data.size() > 0 ) {
1760
 
    // convert CRLF to LF before writing text attachments to disk
1761
 
    const size_t newsize = KMail::Util::crlf2lf( data.data(), data.size() );
1762
 
    data.truncate( newsize );
1763
 
  }
1764
 
  if( !KPIMUtils::kByteArrayToFile( data, fname, false, false, false ) )
1765
 
    return QString();
1766
 
 
1767
 
  mTempFiles.append( fname );
1768
 
  // make file read-only so that nobody gets the impression that he might
1769
 
  // edit attached files (cf. bug #52813)
1770
 
  ::chmod( QFile::encodeName( fname ), S_IRUSR );
1771
 
 
1772
 
  return fname;
1773
 
}
1774
 
 
1775
 
QString KMReaderWin::createTempDir( const QString &param )
1776
 
{
1777
 
  KTemporaryFile *tempFile = new KTemporaryFile();
1778
 
  tempFile->setSuffix( '.' + param );
1779
 
  tempFile->open();
1780
 
  QString fname = tempFile->fileName();
1781
 
  delete tempFile;
1782
 
 
1783
 
  if ( ::access( QFile::encodeName( fname ), W_OK ) != 0 ) {
1784
 
    // Not there or not writable
1785
 
    if( KDE_mkdir( QFile::encodeName( fname ), 0 ) != 0 ||
1786
 
        ::chmod( QFile::encodeName( fname ), S_IRWXU ) != 0 ) {
1787
 
      return QString(); //failed create
1788
 
    }
1789
 
  }
1790
 
 
1791
 
  assert( !fname.isNull() );
1792
 
 
1793
 
  mTempDirs.append( fname );
1794
 
  return fname;
1795
 
}
1796
 
 
1797
 
//-----------------------------------------------------------------------------
1798
 
void KMReaderWin::showVCard( KMMessagePart * msgPart ) {
1799
 
  const QByteArray vCard = msgPart->bodyDecodedBinary();
1800
 
 
1801
 
  VCardViewer *vcv = new VCardViewer(this, vCard );
1802
 
  vcv->setObjectName( "vCardDialog" );
1803
 
  vcv->show();
1804
 
}
1805
 
 
1806
 
//-----------------------------------------------------------------------------
1807
 
void KMReaderWin::printMsg( KMMessage* aMsg )
1808
 
{
1809
 
  disconnect( mPartHtmlWriter, SIGNAL( finished() ), this, SLOT( slotPrintMsg() ) );
1810
 
  connect( mPartHtmlWriter, SIGNAL( finished() ), this, SLOT( slotPrintMsg() ) );
1811
 
  setMsg( aMsg, true );
1812
 
}
1813
 
 
1814
 
//-----------------------------------------------------------------------------
1815
 
void KMReaderWin::slotPrintMsg()
1816
 
{
1817
 
  disconnect( mPartHtmlWriter, SIGNAL( finished() ), this, SLOT( slotPrintMsg() ) );
1818
 
  if (!message()) return;
1819
 
  mViewer->view()->print();
1820
 
  deleteLater();
1821
 
}
1822
 
 
1823
 
 
1824
 
//-----------------------------------------------------------------------------
1825
 
int KMReaderWin::msgPartFromUrl( const KUrl &aUrl )
1826
 
{
1827
 
  if ( aUrl.isEmpty() ) return -1;
1828
 
  if ( !aUrl.isLocalFile() ) return -1;
1829
 
 
1830
 
  QString path = aUrl.toLocalFile();
1831
 
  uint right = path.lastIndexOf( '/' );
1832
 
  uint left = path.lastIndexOf( '.', right );
1833
 
 
1834
 
  bool ok;
1835
 
  int res = path.mid( left + 1, right - left - 1 ).toInt( &ok );
1836
 
  return ( ok ) ? res : -1;
1837
 
}
1838
 
 
1839
 
 
1840
 
//-----------------------------------------------------------------------------
1841
 
void KMReaderWin::resizeEvent( QResizeEvent * )
1842
 
{
1843
 
  if( !mResizeTimer.isActive() )
1844
 
  {
1845
 
    //
1846
 
    // Combine all resize operations that are requested as long a
1847
 
    // the timer runs.
1848
 
    //
1849
 
    mResizeTimer.start( 100 );
1850
 
  }
1851
 
}
1852
 
 
1853
 
 
1854
 
//-----------------------------------------------------------------------------
1855
 
void KMReaderWin::slotDelayedResize()
1856
 
{
1857
 
  mSplitter->setGeometry( 0, 0, width(), height() );
1858
 
}
1859
 
 
1860
 
 
1861
 
//-----------------------------------------------------------------------------
1862
 
void KMReaderWin::slotTouchMessage()
1863
 
{
1864
 
  if ( !message() )
1865
 
    return;
1866
 
 
1867
 
  if ( !message()->status().isNew() && !message()->status().isUnread() )
1868
 
    return;
1869
 
 
1870
 
  SerNumList serNums;
1871
 
  serNums.append( message()->getMsgSerNum() );
1872
 
  KMCommand *command = new KMSetStatusCommand( MessageStatus::statusRead(), serNums );
1873
 
  command->start();
1874
 
 
1875
 
  // should we send an MDN?
1876
 
  if ( mNoMDNsWhenEncrypted &&
1877
 
       message()->encryptionState() != KMMsgNotEncrypted &&
1878
 
       message()->encryptionState() != KMMsgEncryptionStateUnknown )
1879
 
    return;
1880
 
 
1881
 
  KMFolder *folder = message()->parent();
1882
 
  if ( folder &&
1883
 
       ( folder->isOutbox() || folder->isSent() || folder->isTrash() ||
1884
 
         folder->isDrafts() || folder->isTemplates() ) )
1885
 
    return;
1886
 
 
1887
 
  if ( KMMessage * receipt = message()->createMDN( MDN::ManualAction,
1888
 
                                                   MDN::Displayed,
1889
 
                                                   true /* allow GUI */ ) )
1890
 
    if ( !kmkernel->msgSender()->send( receipt ) ) // send or queue
1891
 
      KMessageBox::error( this, i18n("Could not send MDN.") );
1892
 
}
1893
 
 
1894
 
 
1895
 
//-----------------------------------------------------------------------------
1896
 
void KMReaderWin::closeEvent( QCloseEvent *e )
1897
 
{
1898
 
  QWidget::closeEvent( e );
1899
 
  writeConfig();
1900
 
}
1901
 
 
1902
 
 
1903
 
bool foundSMIMEData( const QString aUrl,
1904
 
                     QString& displayName,
1905
 
                     QString& libName,
1906
 
                     QString& keyId )
1907
 
{
1908
 
  static QString showCertMan("showCertificate#");
1909
 
  displayName = "";
1910
 
  libName = "";
1911
 
  keyId = "";
1912
 
  int i1 = aUrl.indexOf( showCertMan );
1913
 
  if( -1 < i1 ) {
1914
 
    i1 += showCertMan.length();
1915
 
    int i2 = aUrl.indexOf(" ### ", i1);
1916
 
    if( i1 < i2 )
1917
 
    {
1918
 
      displayName = aUrl.mid( i1, i2-i1 );
1919
 
      i1 = i2+5;
1920
 
      i2 = aUrl.indexOf(" ### ", i1);
1921
 
      if( i1 < i2 )
1922
 
      {
1923
 
        libName = aUrl.mid( i1, i2-i1 );
1924
 
        i2 += 5;
1925
 
 
1926
 
        keyId = aUrl.mid( i2 );
1927
 
        /*
1928
 
        int len = aUrl.length();
1929
 
        if( len > i2+1 ) {
1930
 
          keyId = aUrl.mid( i2, 2 );
1931
 
          i2 += 2;
1932
 
          while( len > i2+1 ) {
1933
 
            keyId += ':';
1934
 
            keyId += aUrl.mid( i2, 2 );
1935
 
            i2 += 2;
1936
 
          }
1937
 
        }
1938
 
        */
1939
 
      }
1940
 
    }
1941
 
  }
1942
 
  return !keyId.isEmpty();
1943
 
}
1944
 
 
1945
 
 
1946
 
//-----------------------------------------------------------------------------
1947
 
void KMReaderWin::slotUrlOn(const QString &aUrl)
1948
 
{
1949
 
  const KUrl url(aUrl);
1950
 
 
1951
 
  if ( url.protocol() == "kmail" || url.protocol() == "x-kmail" || url.protocol() == "attachment"
1952
 
       || (url.protocol().isEmpty() && url.path().isEmpty()) ) {
1953
 
    mViewer->setDNDEnabled( false );
1954
 
  } else {
1955
 
    mViewer->setDNDEnabled( true );
1956
 
  }
1957
 
 
1958
 
  if ( aUrl.trimmed().isEmpty() ) {
1959
 
    KPIM::BroadcastStatus::instance()->reset();
1960
 
    mHoveredUrl = KUrl();
1961
 
    return;
1962
 
  }
1963
 
 
1964
 
  mHoveredUrl = url;
1965
 
 
1966
 
  const QString msg = URLHandlerManager::instance()->statusBarMessage( url, this );
1967
 
 
1968
 
  if ( msg.isEmpty() ) {
1969
 
    kWarning() << "Unhandled URL hover!";
1970
 
  }
1971
 
  KPIM::BroadcastStatus::instance()->setTransientStatusMsg( msg );
1972
 
}
1973
 
 
1974
 
 
1975
 
//-----------------------------------------------------------------------------
1976
 
void KMReaderWin::slotUrlOpen(const KUrl &aUrl, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)
1977
 
{
1978
 
  mClickedUrl = aUrl;
1979
 
 
1980
 
  if ( URLHandlerManager::instance()->handleClick( aUrl, this ) )
1981
 
    return;
1982
 
 
1983
 
  kWarning() << "Unhandled URL click!";
1984
 
  emit urlClicked( aUrl, Qt::LeftButton );
1985
 
}
1986
 
 
1987
 
//-----------------------------------------------------------------------------
1988
 
void KMReaderWin::slotUrlPopup(const QString &aUrl, const QPoint& aPos)
1989
 
{
1990
 
  const KUrl url( aUrl );
1991
 
  mClickedUrl = url;
1992
 
 
1993
 
  if ( URLHandlerManager::instance()->handleContextMenuRequest( url, aPos, this ) )
1994
 
    return;
1995
 
 
1996
 
  if ( message() ) {
1997
 
    kWarning() << "Unhandled URL right-click!";
1998
 
    emit popupMenu( *message(), url, aPos );
1999
 
  }
2000
 
}
2001
 
 
2002
 
// Checks if the given node has a parent node that is a DIV which has an ID attribute
2003
 
// with the value specified here
2004
 
static bool hasParentDivWithId( const DOM::Node &start, const QString &id )
2005
 
{
2006
 
  if ( start.isNull() )
2007
 
    return false;
2008
 
 
2009
 
  if ( start.nodeName().string() == "div" ) {
2010
 
    for ( unsigned int i = 0; i < start.attributes().length(); i++ ) {
2011
 
      if ( start.attributes().item( i ).nodeName().string() == "id" &&
2012
 
           start.attributes().item( i ).nodeValue().string() == id )
2013
 
        return true;
2014
 
    }
2015
 
  }
2016
 
 
2017
 
  if ( !start.parentNode().isNull() )
2018
 
    return hasParentDivWithId( start.parentNode(), id );
2019
 
  else return false;
2020
 
}
2021
 
 
2022
 
//-----------------------------------------------------------------------------
2023
 
void KMReaderWin::prepareHandleAttachment( int id, const QString& fileName )
2024
 
{
2025
 
  mAtmCurrent = id;
2026
 
  mAtmCurrentName = fileName;
2027
 
}
2028
 
 
2029
 
//-----------------------------------------------------------------------------
2030
 
void KMReaderWin::showAttachmentPopup( int id, const QString & name, const QPoint &p )
2031
 
{
2032
 
  prepareHandleAttachment( id, name );
2033
 
  KMenu *menu = new KMenu();
2034
 
  QAction *action;
2035
 
 
2036
 
  QSignalMapper *attachmentMapper = new QSignalMapper( menu );
2037
 
  connect( attachmentMapper, SIGNAL( mapped( int ) ),
2038
 
           this, SLOT( slotHandleAttachment( int ) ) );
2039
 
 
2040
 
  action = menu->addAction(SmallIcon("document-open"),i18nc("to open", "Open"));
2041
 
  connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2042
 
  attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Open );
2043
 
 
2044
 
  action = menu->addAction(i18n("Open With..."));
2045
 
  connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2046
 
  attachmentMapper->setMapping( action, KMHandleAttachmentCommand::OpenWith );
2047
 
 
2048
 
  action = menu->addAction(i18nc("to view something", "View") );
2049
 
  connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2050
 
  attachmentMapper->setMapping( action, KMHandleAttachmentCommand::View );
2051
 
 
2052
 
  const bool attachmentInHeader = hasParentDivWithId( mViewer->nodeUnderMouse(), "attachmentInjectionPoint" );
2053
 
  const bool hasScrollbar = mViewer->view()->verticalScrollBar()->isVisible();
2054
 
  if ( attachmentInHeader && hasScrollbar ) {
2055
 
    action = menu->addAction( i18n( "Scroll To" ) );
2056
 
    connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2057
 
    attachmentMapper->setMapping( action, KMHandleAttachmentCommand::ScrollTo );
2058
 
  }
2059
 
 
2060
 
  action = menu->addAction(SmallIcon("document-save-as"),i18n("Save As...") );
2061
 
  connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2062
 
  attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Save );
2063
 
 
2064
 
  action = menu->addAction(SmallIcon("edit-copy"), i18n("Copy") );
2065
 
  connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2066
 
  attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Copy );
2067
 
 
2068
 
  const bool canChange = message()->parent() ? !message()->parent()->isReadOnly() : false;
2069
 
 
2070
 
  if ( GlobalSettings::self()->allowAttachmentEditing() ) {
2071
 
    action = menu->addAction(SmallIcon("document-properties"), i18n("Edit Attachment") );
2072
 
    connect( action, SIGNAL(triggered()), attachmentMapper, SLOT(map()) );
2073
 
    attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Edit );
2074
 
    action->setEnabled( canChange );
2075
 
  }
2076
 
  if ( GlobalSettings::self()->allowAttachmentDeletion() ) {
2077
 
    action = menu->addAction(SmallIcon("edit-delete"), i18n("Delete Attachment") );
2078
 
    connect( action, SIGNAL(triggered()), attachmentMapper, SLOT(map()) );
2079
 
    attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Delete );
2080
 
    action->setEnabled( canChange );
2081
 
  }
2082
 
  if ( name.endsWith( QLatin1String(".xia"), Qt::CaseInsensitive ) &&
2083
 
       Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) ) {
2084
 
    action = menu->addAction( i18n( "Decrypt With Chiasmus..." ) );
2085
 
    connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2086
 
    attachmentMapper->setMapping( action, KMHandleAttachmentCommand::ChiasmusEncrypt );
2087
 
  }
2088
 
  action = menu->addAction(i18n("Properties") );
2089
 
  connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2090
 
  attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Properties );
2091
 
  menu->exec( p );
2092
 
  delete menu;
2093
 
}
2094
 
 
2095
 
//-----------------------------------------------------------------------------
2096
 
void KMReaderWin::setStyleDependantFrameWidth()
2097
 
{
2098
 
  if ( !mBox )
2099
 
    return;
2100
 
  // set the width of the frame to a reasonable value for the current GUI style
2101
 
  int frameWidth;
2102
 
#if 0 // is this hack still needed with kde4?
2103
 
  if( !qstrcmp( style()->metaObject()->className(), "KeramikStyle" ) )
2104
 
    frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1;
2105
 
  else
2106
 
#endif
2107
 
    frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
2108
 
  if ( frameWidth < 0 )
2109
 
    frameWidth = 0;
2110
 
  if ( frameWidth != mBox->lineWidth() )
2111
 
    mBox->setLineWidth( frameWidth );
2112
 
}
2113
 
 
2114
 
//-----------------------------------------------------------------------------
2115
 
void KMReaderWin::styleChange( QStyle& oldStyle )
2116
 
{
2117
 
  setStyleDependantFrameWidth();
2118
 
  QWidget::styleChange( oldStyle );
2119
 
}
2120
 
 
2121
 
//-----------------------------------------------------------------------------
2122
 
void KMReaderWin::slotHandleAttachment( int choice )
2123
 
{
2124
 
  mAtmUpdate = true;
2125
 
  partNode* node = mRootNode ? mRootNode->findId( mAtmCurrent ) : 0;
2126
 
  if ( choice == KMHandleAttachmentCommand::Delete ) {
2127
 
    slotDeleteAttachment( node );
2128
 
  } else if ( choice == KMHandleAttachmentCommand::Edit ) {
2129
 
    slotEditAttachment( node );
2130
 
  } else if ( choice == KMHandleAttachmentCommand::Copy ) {
2131
 
    if ( !node )
2132
 
      return;
2133
 
    QList<QUrl> urls;
2134
 
    KUrl kUrl = tempFileUrlFromPartNode( node );
2135
 
    QUrl url = QUrl::fromPercentEncoding( kUrl.toEncoded() );
2136
 
 
2137
 
    if ( !url.isValid() )
2138
 
      return;
2139
 
    urls.append( url );
2140
 
 
2141
 
    QMimeData *mimeData = new QMimeData;
2142
 
    mimeData->setUrls( urls );
2143
 
    QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard );
2144
 
  } else if ( choice == KMHandleAttachmentCommand::ScrollTo ) {
2145
 
    scrollToAttachment( node );
2146
 
  }
2147
 
  else {
2148
 
    KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand(
2149
 
        node, message(), mAtmCurrent, mAtmCurrentName,
2150
 
        KMHandleAttachmentCommand::AttachmentAction( choice ), KService::Ptr( 0 ), this );
2151
 
    connect( command, SIGNAL( showAttachment( int, const QString& ) ),
2152
 
        this, SLOT( slotAtmView( int, const QString& ) ) );
2153
 
    command->start();
2154
 
  }
2155
 
}
2156
 
 
2157
 
//-----------------------------------------------------------------------------
2158
 
void KMReaderWin::slotToggleHtmlMode()
2159
 
{
2160
 
  setHtmlOverride( !htmlMail() );
2161
 
  update( true );
2162
 
}
2163
 
 
2164
369
//-----------------------------------------------------------------------------
2165
370
void KMReaderWin::slotFind()
2166
371
{
2167
 
  mViewer->findText();
2168
 
}
2169
 
 
2170
 
//-----------------------------------------------------------------------------
2171
 
void KMReaderWin::slotToggleFixedFont()
2172
 
{
2173
 
  mUseFixedFont = !mUseFixedFont;
2174
 
  update( true );
2175
 
}
2176
 
 
2177
 
//-----------------------------------------------------------------------------
2178
 
void KMReaderWin::slotToggleMimePartTree()
2179
 
{
2180
 
  if ( mToggleMimePartTreeAction->isChecked() )
2181
 
    GlobalSettings::self()->setMimeTreeMode( GlobalSettings::EnumMimeTreeMode::Always );
2182
 
  else
2183
 
    GlobalSettings::self()->setMimeTreeMode( GlobalSettings::EnumMimeTreeMode::Never );
2184
 
  showHideMimeTree();
2185
 
}
2186
 
 
 
372
  mViewer->slotFind();
 
373
}
2187
374
//-----------------------------------------------------------------------------
2188
375
void KMReaderWin::slotCopySelectedText()
2189
376
{
2192
379
  QApplication::clipboard()->setText( selection );
2193
380
}
2194
381
 
2195
 
 
2196
 
//-----------------------------------------------------------------------------
2197
 
void KMReaderWin::atmViewMsg( KMMessagePart* aMsgPart, int nodeId )
2198
 
{
2199
 
  assert(aMsgPart!=0);
2200
 
  KMMessage* msg = new KMMessage;
2201
 
  msg->fromString(aMsgPart->bodyDecoded());
2202
 
  assert(msg != 0);
2203
 
  msg->setMsgSerNum( 0 ); // because lookups will fail
2204
 
  // some information that is needed for imap messages with LOD
2205
 
  msg->setParent( message()->parent() );
2206
 
  msg->setUID(message()->UID());
2207
 
  msg->setReadyToShow(true);
2208
 
  KMReaderMainWin *win = new KMReaderMainWin();
2209
 
  win->showMsg( overrideEncoding(), msg, message()->getMsgSerNum(), nodeId );
2210
 
  win->show();
2211
 
}
2212
 
 
2213
 
 
2214
 
void KMReaderWin::setMsgPart( partNode * node ) {
2215
 
  htmlWriter()->reset();
2216
 
  mColorBar->hide();
2217
 
  htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
2218
 
  htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
2219
 
  // end ###
2220
 
  if ( node ) {
2221
 
    ObjectTreeParser otp( this, 0, true );
2222
 
    otp.parseObjectTree( node );
2223
 
  }
2224
 
  // ### this, too
2225
 
  htmlWriter()->queue( "</body></html>" );
2226
 
  htmlWriter()->flush();
2227
 
}
2228
 
 
2229
 
//-----------------------------------------------------------------------------
2230
 
void KMReaderWin::setMsgPart( KMMessagePart* aMsgPart, bool aHTML,
2231
 
                              const QString& aFileName, const QString& pname )
2232
 
{
2233
 
  // Cancel scheduled updates of the reader window, as that would stop the
2234
 
  // timer of the HTML writer, which would make viewing attachment not work
2235
 
  // anymore as not all HTML is written to the HTML part.
2236
 
  // We're updating the reader window here ourselves anyway.
2237
 
  mUpdateReaderWinTimer.stop();
2238
 
 
2239
 
  KCursorSaver busy(KBusyPtr::busy());
2240
 
  if (kasciistricmp(aMsgPart->typeStr(), "message")==0) {
2241
 
      // if called from compose win
2242
 
      KMMessage* msg = new KMMessage;
2243
 
      assert(aMsgPart!=0);
2244
 
      msg->fromString(aMsgPart->bodyDecoded());
2245
 
      mMainWindow->setWindowTitle(msg->subject());
2246
 
      setMsg(msg, true);
2247
 
      setAutoDelete(true);
2248
 
  } else if (kasciistricmp(aMsgPart->typeStr(), "text")==0) {
2249
 
      if (kasciistricmp(aMsgPart->subtypeStr(), "x-vcard") == 0 ||
2250
 
          kasciistricmp(aMsgPart->subtypeStr(), "directory") == 0) {
2251
 
        showVCard( aMsgPart );
2252
 
        return;
2253
 
      }
2254
 
      htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
2255
 
      htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
2256
 
 
2257
 
      if (aHTML && (kasciistricmp(aMsgPart->subtypeStr(), "html")==0)) { // HTML
2258
 
        // ### this is broken. It doesn't stip off the HTML header and footer!
2259
 
        htmlWriter()->queue( aMsgPart->bodyToUnicode( overrideCodec() ) );
2260
 
        mColorBar->setHtmlMode();
2261
 
      } else { // plain text
2262
 
        const QByteArray str = aMsgPart->bodyDecoded();
2263
 
        ObjectTreeParser otp( this );
2264
 
        otp.writeBodyStr( str,
2265
 
                          overrideCodec() ? overrideCodec() : aMsgPart->codec(),
2266
 
                          message() ? message()->from() : QString() );
2267
 
      }
2268
 
      htmlWriter()->queue("</body></html>");
2269
 
      htmlWriter()->flush();
2270
 
      mMainWindow->setWindowTitle(i18n("View Attachment: %1", pname));
2271
 
  } else if (kasciistricmp(aMsgPart->typeStr(), "image")==0 ||
2272
 
             (kasciistricmp(aMsgPart->typeStr(), "application")==0 &&
2273
 
              kasciistricmp(aMsgPart->subtypeStr(), "postscript")==0))
2274
 
  {
2275
 
      if (aFileName.isEmpty()) return;  // prevent crash
2276
 
      // Open the window with a size so the image fits in (if possible):
2277
 
      QImageReader *iio = new QImageReader();
2278
 
      iio->setFileName(aFileName);
2279
 
      if( iio->canRead() ) {
2280
 
          QImage img = iio->read();
2281
 
          QRect desk = KGlobalSettings::desktopGeometry(mMainWindow);
2282
 
          // determine a reasonable window size
2283
 
          int width, height;
2284
 
          if( img.width() < 50 )
2285
 
              width = 70;
2286
 
          else if( img.width()+20 < desk.width() )
2287
 
              width = img.width()+20;
2288
 
          else
2289
 
              width = desk.width();
2290
 
          if( img.height() < 50 )
2291
 
              height = 70;
2292
 
          else if( img.height()+20 < desk.height() )
2293
 
              height = img.height()+20;
2294
 
          else
2295
 
              height = desk.height();
2296
 
          mMainWindow->resize( width, height );
2297
 
      }
2298
 
      // Just write the img tag to HTML:
2299
 
      htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
2300
 
      htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
2301
 
      htmlWriter()->write( "<img src=\"file:" +
2302
 
                           KUrl::toPercentEncoding( aFileName ) +
2303
 
                           "\" border=\"0\">\n"
2304
 
                           "</body></html>\n" );
2305
 
      htmlWriter()->end();
2306
 
      setWindowTitle( i18n("View Attachment: %1", pname ) );
2307
 
      show();
2308
 
      delete iio;
2309
 
  } else {
2310
 
    htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
2311
 
    htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
2312
 
    htmlWriter()->queue( "<pre>" );
2313
 
 
2314
 
    QString str = aMsgPart->bodyDecoded();
2315
 
    // A QString cannot handle binary data. So if it's shorter than the
2316
 
    // attachment, we assume the attachment is binary:
2317
 
    if( str.length() < aMsgPart->decodedSize() ) {
2318
 
      str.prepend( i18np("[KMail: Attachment contains binary data. Trying to show first character.]",
2319
 
          "[KMail: Attachment contains binary data. Trying to show first %1 characters.]",
2320
 
                               str.length()) + QChar::fromLatin1('\n') );
2321
 
    }
2322
 
    htmlWriter()->queue( Qt::escape( str ) );
2323
 
    htmlWriter()->queue( "</pre>" );
2324
 
    htmlWriter()->queue("</body></html>");
2325
 
    htmlWriter()->flush();
2326
 
    mMainWindow->setWindowTitle(i18n("View Attachment: %1", pname));
2327
 
  }
2328
 
}
2329
 
 
2330
 
 
2331
 
//-----------------------------------------------------------------------------
2332
 
void KMReaderWin::slotAtmView( int id, const QString& name )
2333
 
{
2334
 
  partNode* node = mRootNode ? mRootNode->findId( id ) : 0;
2335
 
  if( node ) {
2336
 
    mAtmCurrent = id;
2337
 
    mAtmCurrentName = name;
2338
 
    if ( mAtmCurrentName.isEmpty() )
2339
 
      mAtmCurrentName = tempFileUrlFromPartNode( node ).toLocalFile();
2340
 
 
2341
 
    KMMessagePart& msgPart = node->msgPart();
2342
 
    QString pname = msgPart.fileName();
2343
 
    if (pname.isEmpty()) pname=msgPart.name();
2344
 
    if (pname.isEmpty()) pname=msgPart.contentDescription();
2345
 
    if (pname.isEmpty()) pname="unnamed";
2346
 
    // image Attachment is saved already
2347
 
    if (kasciistricmp(msgPart.typeStr(), "message")==0) {
2348
 
      atmViewMsg( &msgPart,id );
2349
 
    } else if ((kasciistricmp(msgPart.typeStr(), "text")==0) &&
2350
 
               ( (kasciistricmp(msgPart.subtypeStr(), "x-vcard")==0) ||
2351
 
                 (kasciistricmp(msgPart.subtypeStr(), "directory")==0) )) {
2352
 
      setMsgPart( &msgPart, htmlMail(), name, pname );
2353
 
    } else {
2354
 
      KMReaderMainWin *win = new KMReaderMainWin(&msgPart, htmlMail(),
2355
 
          name, pname, overrideEncoding() );
2356
 
      win->show();
2357
 
    }
2358
 
  }
2359
 
}
2360
 
 
2361
 
//-----------------------------------------------------------------------------
2362
 
void KMReaderWin::openAttachment( int id, const QString & name )
2363
 
{
2364
 
  mAtmCurrentName = name;
2365
 
  mAtmCurrent = id;
2366
 
 
2367
 
  QString str, pname, cmd, fileName;
2368
 
 
2369
 
  partNode* node = mRootNode ? mRootNode->findId( id ) : 0;
2370
 
  if( !node ) {
2371
 
    kWarning() << "Could not find node" << id;
2372
 
    return;
2373
 
  }
2374
 
  if ( mAtmCurrentName.isEmpty() )
2375
 
    mAtmCurrentName = tempFileUrlFromPartNode( node ).toLocalFile();
2376
 
 
2377
 
  KMMessagePart& msgPart = node->msgPart();
2378
 
  if (kasciistricmp(msgPart.typeStr(), "message")==0)
2379
 
  {
2380
 
    atmViewMsg( &msgPart, id );
2381
 
    return;
2382
 
  }
2383
 
 
2384
 
  QByteArray contentTypeStr( msgPart.typeStr() + '/' + msgPart.subtypeStr() );
2385
 
  kAsciiToLower( contentTypeStr.data() );
2386
 
 
2387
 
  // determine the MIME type of the attachment
2388
 
  KMimeType::Ptr mimetype;
2389
 
  // prefer the value of the Content-Type header
2390
 
  mimetype = KMimeType::mimeType( QString::fromLatin1( contentTypeStr ), KMimeType::ResolveAliases );
2391
 
  if ( !mimetype.isNull() && mimetype->is( KABC::Addressee::mimeType() ) ) {
2392
 
    showVCard( &msgPart );
2393
 
    return;
2394
 
  }
2395
 
 
2396
 
  // special case treatment on mac
2397
 
  if ( KMail::Util::handleUrlOnMac( mAtmCurrentName ) )
2398
 
    return;
2399
 
 
2400
 
  if ( mimetype.isNull() || mimetype->name() == "application/octet-stream" ) {
2401
 
    // consider the filename if mimetype can not be found by content-type
2402
 
    mimetype = KMimeType::findByPath( name, 0, true /* no disk access */ );
2403
 
  }
2404
 
  if ( ( mimetype->name() == "application/octet-stream" )
2405
 
       && msgPart.isComplete() ) {
2406
 
    // consider the attachment's contents if neither the Content-Type header
2407
 
    // nor the filename give us a clue
2408
 
    mimetype = KMimeType::findByFileContent( name );
2409
 
  }
2410
 
 
2411
 
  KService::Ptr offer =
2412
 
      KMimeTypeTrader::self()->preferredService( mimetype->name(), "Application" );
2413
 
 
2414
 
  QString filenameText = msgPart.fileName();
2415
 
  if ( filenameText.isEmpty() )
2416
 
    filenameText = msgPart.name();
2417
 
 
2418
 
  KMail::AttachmentDialog dialog( this, filenameText, offer ? offer->name() : QString(),
2419
 
                                  QString::fromLatin1( "askSave_" ) + mimetype->name() );
2420
 
  const int choice = dialog.exec();
2421
 
 
2422
 
  if ( choice == KMail::AttachmentDialog::Save ) {
2423
 
    mAtmUpdate = true;
2424
 
    KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand( node,
2425
 
        message(), mAtmCurrent, mAtmCurrentName, KMHandleAttachmentCommand::Save,
2426
 
        offer, this );
2427
 
    connect( command, SIGNAL( showAttachment( int, const QString& ) ),
2428
 
        this, SLOT( slotAtmView( int, const QString& ) ) );
2429
 
    command->start();
2430
 
  }
2431
 
  else if ( ( choice == KMail::AttachmentDialog::Open ) ||
2432
 
            ( choice == KMail::AttachmentDialog::OpenWith ) ) {
2433
 
    KMHandleAttachmentCommand::AttachmentAction action;
2434
 
    if ( choice == KMail::AttachmentDialog::Open )
2435
 
      action = KMHandleAttachmentCommand::Open;
2436
 
    else
2437
 
      action = KMHandleAttachmentCommand::OpenWith;
2438
 
    mAtmUpdate = true;
2439
 
    KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand( node,
2440
 
        message(), mAtmCurrent, mAtmCurrentName, action, offer, this );
2441
 
    connect( command, SIGNAL( showAttachment( int, const QString& ) ),
2442
 
        this, SLOT( slotAtmView( int, const QString& ) ) );
2443
 
    command->start();
2444
 
  } else { // Cancel
2445
 
    kDebug() << "Canceled opening attachment";
2446
 
  }
2447
 
}
2448
 
 
2449
 
//-----------------------------------------------------------------------------
2450
 
void KMReaderWin::slotScrollUp()
2451
 
{
2452
 
  mViewer->view()->scrollBy( 0, -10 );
2453
 
}
2454
 
 
2455
 
 
2456
 
//-----------------------------------------------------------------------------
2457
 
void KMReaderWin::slotScrollDown()
2458
 
{
2459
 
  mViewer->view()->scrollBy( 0, 10 );
2460
 
}
2461
 
 
2462
 
bool KMReaderWin::atBottom() const
2463
 
{
2464
 
  KHTMLView *view = mViewer->view();
2465
 
  return view->contentsY() + view->visibleHeight() >= view->contentsHeight();
2466
 
}
2467
 
 
2468
 
//-----------------------------------------------------------------------------
2469
 
void KMReaderWin::slotJumpDown()
2470
 
{
2471
 
  mViewer->view()->scrollBy( 0, mViewer->view()->visibleHeight() );
2472
 
}
2473
 
 
2474
 
//-----------------------------------------------------------------------------
2475
 
void KMReaderWin::slotScrollPrior()
2476
 
{
2477
 
  mViewer->view()->scrollBy( 0, -(int)(mViewer->widget()->height() * 0.8 ) );
2478
 
}
2479
 
 
2480
 
//-----------------------------------------------------------------------------
2481
 
void KMReaderWin::slotScrollNext()
2482
 
{
2483
 
  mViewer->view()->scrollBy( 0, (int)(mViewer->widget()->height() * 0.8 ) );
2484
 
}
2485
 
 
2486
 
//-----------------------------------------------------------------------------
2487
 
void KMReaderWin::slotDocumentChanged()
2488
 
{
2489
 
 
2490
 
}
2491
 
 
2492
 
//-----------------------------------------------------------------------------
2493
 
void KMReaderWin::slotTextSelected(bool)
2494
 
{
2495
 
  QString temp = mViewer->selectedText();
2496
 
  QApplication::clipboard()->setText(temp);
2497
 
}
2498
 
 
2499
 
//-----------------------------------------------------------------------------
2500
 
void KMReaderWin::selectAll()
2501
 
{
2502
 
  mViewer->selectAll();
2503
 
}
2504
 
 
2505
 
//-----------------------------------------------------------------------------
2506
 
QString KMReaderWin::copyText()
2507
 
{
2508
 
  QString temp = mViewer->selectedText();
2509
 
  return temp;
2510
 
}
2511
 
 
2512
 
//-----------------------------------------------------------------------------
2513
 
void KMReaderWin::slotDocumentDone()
2514
 
{
 
382
//-----------------------------------------------------------------------------
 
383
void KMReaderWin::setMsgPart( KMime::Content* aMsgPart )
 
384
{
 
385
  mViewer->setMessagePart( aMsgPart );
 
386
}
 
387
 
 
388
//-----------------------------------------------------------------------------
 
389
QString KMReaderWin::copyText() const
 
390
{
 
391
  return mViewer->selectedText();
2515
392
}
2516
393
 
2517
394
//-----------------------------------------------------------------------------
2518
395
void KMReaderWin::setHtmlOverride( bool override )
2519
396
{
2520
 
  mHtmlOverride = override;
2521
 
  if ( message() ) {
2522
 
    message()->setDecodeHTML( htmlMail() );
2523
 
  }
 
397
  mViewer->setHtmlOverride( override );
 
398
}
2524
399
 
2525
 
  // keep toggle display mode action state in sync.
2526
 
  if ( mToggleDisplayModeAction )
2527
 
    mToggleDisplayModeAction->setChecked( htmlMail() );
 
400
bool KMReaderWin::htmlOverride() const
 
401
{
 
402
  return mViewer->htmlOverride();
2528
403
}
2529
404
 
2530
405
//-----------------------------------------------------------------------------
2531
406
void KMReaderWin::setHtmlLoadExtOverride( bool override )
2532
407
{
2533
 
  mHtmlLoadExtOverride = override;
 
408
  mViewer->setHtmlLoadExtOverride( override );
2534
409
}
2535
410
 
2536
411
//-----------------------------------------------------------------------------
2537
 
bool KMReaderWin::htmlMail()
 
412
bool KMReaderWin::htmlMail() const
2538
413
{
2539
 
  return ((mHtmlMail && !mHtmlOverride) || (!mHtmlMail && mHtmlOverride));
 
414
  return mViewer->htmlMail();
2540
415
}
2541
416
 
2542
417
//-----------------------------------------------------------------------------
2543
418
bool KMReaderWin::htmlLoadExternal()
2544
419
{
2545
 
  return ((mHtmlLoadExternal && !mHtmlLoadExtOverride) ||
2546
 
          (!mHtmlLoadExternal && mHtmlLoadExtOverride));
2547
 
}
2548
 
 
2549
 
//-----------------------------------------------------------------------------
2550
 
void KMReaderWin::saveRelativePosition()
2551
 
{
2552
 
  const QScrollBar *scrollBar = mViewer->view()->verticalScrollBar();
2553
 
  if ( scrollBar->maximum() )
2554
 
    mSavedRelativePosition = static_cast<float>( scrollBar->value() ) / scrollBar->maximum();
2555
 
  else
2556
 
    mSavedRelativePosition = 0;
2557
 
}
2558
 
 
2559
 
 
2560
 
//-----------------------------------------------------------------------------
2561
 
void KMReaderWin::update( bool force )
2562
 
{
2563
 
  KMMessage *msg = message();
2564
 
  if ( msg ) {
2565
 
    saveRelativePosition();
2566
 
    setMsg( msg, force );
2567
 
  }
2568
 
}
2569
 
 
2570
 
//-----------------------------------------------------------------------------
2571
 
KMMessage *KMReaderWin::message() const
2572
 
{
2573
 
  if ( mMessage ) {
2574
 
    return mMessage;
2575
 
  }
2576
 
 
2577
 
  KMMessage *message = 0;
2578
 
  if ( mLastSerNum ) {
2579
 
    KMFolder *folder;
2580
 
    int index;
2581
 
    KMMsgDict::instance()->getLocation( mLastSerNum, &folder, &index );
2582
 
    if ( folder && index >= 0 ) {
2583
 
      message = folder->getMsg( index );
2584
 
    }
2585
 
    if ( !message ) {
2586
 
      kWarning() << "Attempt to reference invalid serial number" << mLastSerNum;
2587
 
    }
2588
 
  }
2589
 
  return message;
2590
 
}
2591
 
 
2592
 
//-----------------------------------------------------------------------------
2593
 
void KMReaderWin::slotUrlClicked()
2594
 
{
2595
 
  KMMainWidget *mainWidget = dynamic_cast<KMMainWidget*>(mMainWindow);
2596
 
  uint identity = 0;
2597
 
  if ( message() && message()->parent() ) {
2598
 
    identity = message()->parent()->identity();
2599
 
  }
2600
 
 
2601
 
  KMCommand *command = new KMUrlClickedCommand( mClickedUrl, identity, this,
2602
 
                                                false, mainWidget );
2603
 
  command->start();
 
420
  return mViewer->htmlLoadExternal();
 
421
}
 
422
 
 
423
//-----------------------------------------------------------------------------
 
424
Akonadi::Item KMReaderWin::message() const
 
425
{
 
426
  return mViewer->messageItem();
2604
427
}
2605
428
 
2606
429
//-----------------------------------------------------------------------------
2607
430
void KMReaderWin::slotMailtoCompose()
2608
431
{
2609
 
  KMCommand *command = new KMMailtoComposeCommand( mClickedUrl, message() );
 
432
  KMCommand *command = new KMMailtoComposeCommand( urlClicked(), message() );
2610
433
  command->start();
2611
434
}
2612
435
 
2613
436
//-----------------------------------------------------------------------------
2614
437
void KMReaderWin::slotMailtoForward()
2615
438
{
2616
 
  KMCommand *command = new KMMailtoForwardCommand( mMainWindow, mClickedUrl,
 
439
  KMCommand *command = new KMMailtoForwardCommand( mMainWindow, urlClicked(),
2617
440
                                                   message() );
2618
441
  command->start();
2619
442
}
2621
444
//-----------------------------------------------------------------------------
2622
445
void KMReaderWin::slotMailtoAddAddrBook()
2623
446
{
2624
 
  KMCommand *command = new KMMailtoAddAddrBookCommand( mClickedUrl,
2625
 
                                                       mMainWindow );
2626
 
  command->start();
 
447
  const QString emailString = KPIMUtils::decodeMailtoUrl( urlClicked() );
 
448
 
 
449
  KPIM::AddEmailAddressJob *job = new KPIM::AddEmailAddressJob( emailString, mMainWindow, this );
 
450
  job->start();
2627
451
}
2628
452
 
2629
453
//-----------------------------------------------------------------------------
2630
454
void KMReaderWin::slotMailtoOpenAddrBook()
2631
455
{
2632
 
  KMCommand *command = new KMMailtoOpenAddrBookCommand( mClickedUrl,
2633
 
                                                        mMainWindow );
2634
 
  command->start();
2635
 
}
2636
 
 
2637
 
//-----------------------------------------------------------------------------
2638
 
void KMReaderWin::slotUrlCopy()
2639
 
{
2640
 
  // we don't necessarily need a mainWidget for KMUrlCopyCommand so
2641
 
  // it doesn't matter if the dynamic_cast fails.
2642
 
  KMCommand *command =
2643
 
    new KMUrlCopyCommand( mClickedUrl,
2644
 
                          dynamic_cast<KMMainWidget*>( mMainWindow ) );
2645
 
  command->start();
2646
 
}
2647
 
 
2648
 
//-----------------------------------------------------------------------------
2649
 
void KMReaderWin::slotUrlOpen( const KUrl &url )
2650
 
{
2651
 
  if ( !url.isEmpty() )
2652
 
    mClickedUrl = url;
2653
 
  KMCommand *command = new KMUrlOpenCommand( mClickedUrl, this );
2654
 
  command->start();
 
456
  const QString emailString = KPIMUtils::decodeMailtoUrl( urlClicked() );
 
457
 
 
458
  KPIM::OpenEmailAddressJob *job = new KPIM::OpenEmailAddressJob( emailString, mMainWindow, this );
 
459
  job->start();
2655
460
}
2656
461
 
2657
462
//-----------------------------------------------------------------------------
2658
463
void KMReaderWin::slotAddBookmarks()
2659
464
{
2660
 
    KMCommand *command = new KMAddBookmarksCommand( mClickedUrl, this );
 
465
    KMCommand *command = new KMAddBookmarksCommand( urlClicked(), this );
2661
466
    command->start();
2662
467
}
2663
468
 
2664
469
//-----------------------------------------------------------------------------
2665
470
void KMReaderWin::slotUrlSave()
2666
471
{
2667
 
  KMCommand *command = new KMUrlSaveCommand( mClickedUrl, mMainWindow );
 
472
  KMCommand *command = new KMUrlSaveCommand( urlClicked(), mMainWindow );
2668
473
  command->start();
2669
474
}
2670
475
 
2671
476
//-----------------------------------------------------------------------------
2672
477
void KMReaderWin::slotMailtoReply()
2673
478
{
2674
 
  KMCommand *command = new KMMailtoReplyCommand( mMainWindow, mClickedUrl,
 
479
  KMCommand *command = new KMMailtoReplyCommand( mMainWindow, urlClicked(),
2675
480
                                                 message(), copyText() );
2676
481
  command->start();
2677
482
}
2678
483
 
2679
 
//-----------------------------------------------------------------------------
2680
 
partNode * KMReaderWin::partNodeFromUrl( const KUrl & url ) {
2681
 
  return mRootNode ? mRootNode->findId( msgPartFromUrl( url ) ) : 0 ;
2682
 
}
2683
 
 
2684
 
partNode * KMReaderWin::partNodeForId( int id ) {
2685
 
  return mRootNode ? mRootNode->findId( id ) : 0 ;
2686
 
}
2687
 
 
2688
 
 
2689
 
KUrl KMReaderWin::tempFileUrlFromPartNode( const partNode *node )
2690
 
{
2691
 
  if (!node)
2692
 
    return KUrl();
2693
 
 
2694
 
  foreach ( const QString &path, mTempFiles ) {
2695
 
    int right = path.lastIndexOf( '/' );
2696
 
    int left = path.lastIndexOf( '.', right );
2697
 
 
2698
 
    bool ok = false;
2699
 
    int res = path.mid( left + 1, right - left - 1 ).toInt( &ok );
2700
 
    if ( ok && res == node->nodeId() )
2701
 
      return KUrl( path );
2702
 
  }
2703
 
  return KUrl();
2704
 
}
2705
 
 
2706
 
//-----------------------------------------------------------------------------
2707
 
void KMReaderWin::slotSaveAttachments()
2708
 
{
2709
 
  mAtmUpdate = true;
2710
 
  KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand( mMainWindow,
2711
 
                                                                        message() );
2712
 
  saveCommand->start();
2713
 
}
2714
 
 
2715
 
//-----------------------------------------------------------------------------
2716
 
void KMReaderWin::saveAttachment( const KUrl &tempFileName )
2717
 
{
2718
 
  mAtmCurrent = msgPartFromUrl( tempFileName );
2719
 
  mAtmCurrentName = mClickedUrl.toLocalFile();
2720
 
  slotHandleAttachment( KMHandleAttachmentCommand::Save ); // save
2721
 
}
2722
 
 
2723
 
//-----------------------------------------------------------------------------
2724
 
void KMReaderWin::slotSaveMsg()
2725
 
{
2726
 
  KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( mMainWindow, message() );
2727
 
 
2728
 
  if (saveCommand->url().isEmpty())
2729
 
    delete saveCommand;
2730
 
  else
2731
 
    saveCommand->start();
2732
 
}
2733
 
 
2734
 
//-----------------------------------------------------------------------------
2735
 
bool KMReaderWin::eventFilter( QObject *, QEvent *e )
2736
 
{
2737
 
  if ( e->type() == QEvent::MouseButtonPress ) {
2738
 
    QMouseEvent* me = static_cast<QMouseEvent*>(e);
2739
 
    if ( me->button() == Qt::LeftButton && ( me->modifiers() & Qt::ShiftModifier ) ) {
2740
 
      // special processing for shift+click
2741
 
      URLHandlerManager::instance()->handleShiftClick( mHoveredUrl, this );
2742
 
      return true;
2743
 
    }
2744
 
 
2745
 
    if ( me->button() == Qt::LeftButton ) {
2746
 
      mCanStartDrag = URLHandlerManager::instance()->willHandleDrag( mHoveredUrl, this );
2747
 
      mLastClickPosition = me->pos();
2748
 
    }
2749
 
  }
2750
 
 
2751
 
  if ( e->type() ==  QEvent::MouseButtonRelease ) {
2752
 
    mCanStartDrag = false;
2753
 
  }
2754
 
 
2755
 
  if ( e->type() == QEvent::MouseMove ) {
2756
 
    QMouseEvent* me = static_cast<QMouseEvent*>( e );
2757
 
 
2758
 
    if ( ( mLastClickPosition - me->pos() ).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
2759
 
      if ( mCanStartDrag && !mHoveredUrl.isEmpty() && mHoveredUrl.protocol() == "attachment" ) {
2760
 
        mCanStartDrag = false;
2761
 
        URLHandlerManager::instance()->handleDrag( mHoveredUrl, this );
2762
 
        slotUrlOn( QString() );
2763
 
        return true;
2764
 
      }
2765
 
    }
2766
 
  }
2767
 
 
2768
 
  // standard event processing
2769
 
  return false;
2770
 
}
2771
 
 
2772
 
void KMReaderWin::fillCommandInfo( partNode *node, KMMessage **msg, int *nodeId )
2773
 
{
2774
 
  Q_ASSERT( msg && nodeId );
2775
 
 
2776
 
  if ( mSerNumOfOriginalMessage != 0 ) {
2777
 
    KMFolder *folder = 0;
2778
 
    int index = -1;
2779
 
    KMMsgDict::instance()->getLocation( mSerNumOfOriginalMessage, &folder, &index );
2780
 
    if ( folder && index != -1 )
2781
 
      *msg = folder->getMsg( index );
2782
 
 
2783
 
    if ( !( *msg ) ) {
2784
 
      kWarning() << "Unable to find the original message, aborting attachment deletion!";
2785
 
      return;
2786
 
    }
2787
 
 
2788
 
    *nodeId = node->nodeId() + mNodeIdOffset;
2789
 
  }
2790
 
  else {
2791
 
    *nodeId = node->nodeId();
2792
 
    *msg = message();
2793
 
  }
2794
 
}
2795
 
 
2796
 
void KMReaderWin::slotDeleteAttachment(partNode * node)
2797
 
{
2798
 
  if ( KMessageBox::warningContinueCancel( this,
2799
 
       i18n("Deleting an attachment might invalidate any digital signature on this message."),
2800
 
       i18n("Delete Attachment"), KStandardGuiItem::del(), KStandardGuiItem::cancel(),
2801
 
       "DeleteAttachmentSignatureWarning" )
2802
 
     != KMessageBox::Continue ) {
2803
 
    return;
2804
 
  }
2805
 
 
2806
 
  int nodeId = -1;
2807
 
  KMMessage *msg = 0;
2808
 
  fillCommandInfo( node, &msg, &nodeId );
2809
 
  if ( msg && nodeId != -1 ) {
2810
 
    KMDeleteAttachmentCommand* command = new KMDeleteAttachmentCommand( nodeId, msg, this );
2811
 
    command->start();
2812
 
  }
2813
 
 
2814
 
  // If we are operating on a copy of parts of the message, make sure to update the copy as well.
2815
 
  if ( mSerNumOfOriginalMessage != 0 && message() ) {
2816
 
    message()->deleteBodyPart( node->nodeId() );
2817
 
    update( true );
2818
 
  }
2819
 
}
2820
 
 
2821
 
void KMReaderWin::slotEditAttachment(partNode * node)
2822
 
{
2823
 
  if ( KMessageBox::warningContinueCancel( this,
2824
 
        i18n("Modifying an attachment might invalidate any digital signature on this message."),
2825
 
        i18n("Edit Attachment"), KGuiItem( i18n("Edit"), "document-properties" ), KStandardGuiItem::cancel(),
2826
 
        "EditAttachmentSignatureWarning" )
2827
 
        != KMessageBox::Continue ) {
2828
 
    return;
2829
 
  }
2830
 
 
2831
 
  int nodeId = -1;
2832
 
  KMMessage *msg = 0;
2833
 
  fillCommandInfo( node, &msg, &nodeId );
2834
 
  if ( msg && nodeId != -1 ) {
2835
 
    KMEditAttachmentCommand* command = new KMEditAttachmentCommand( nodeId, msg, this );
2836
 
    command->start();
2837
 
  }
2838
 
 
2839
 
  // FIXME: If we are operating on a copy of parts of the message, make sure to update the copy as well.
2840
 
}
2841
 
 
2842
 
KMail::CSSHelper* KMReaderWin::cssHelper() const
2843
 
{
2844
 
  return mCSSHelper;
2845
 
}
2846
 
 
2847
 
bool KMReaderWin::decryptMessage() const
2848
 
{
2849
 
  if ( !GlobalSettings::self()->alwaysDecrypt() )
2850
 
    return mDecrytMessageOverwrite;
2851
 
  return true;
2852
 
}
2853
 
 
2854
 
void KMReaderWin::scrollToAttachment( const partNode *node )
2855
 
{
2856
 
  DOM::Document doc = mViewer->htmlDocument();
2857
 
 
2858
 
  // The anchors for this are created in ObjectTreeParser::parseObjectTree()
2859
 
  mViewer->gotoAnchor( QString::fromLatin1( "att%1" ).arg( node->nodeId() ) );
2860
 
 
2861
 
  // Remove any old color markings which might be there
2862
 
  const partNode *root = node->topLevelParent();
2863
 
  for ( int i = 0; i <= root->totalChildCount() + 1; i++ ) {
2864
 
    DOM::Element attachmentDiv = doc.getElementById( QString( "attachmentDiv%1" ).arg( i + 1 ) );
2865
 
    if ( !attachmentDiv.isNull() )
2866
 
      attachmentDiv.removeAttribute( "style" );
2867
 
  }
2868
 
 
2869
 
  // Now, color the div of the attachment in yellow, so that the user sees what happened.
2870
 
  // We created a special marked div for this in writeAttachmentMarkHeader() in ObjectTreeParser,
2871
 
  // find and modify that now.
2872
 
  DOM::Element attachmentDiv = doc.getElementById( QString( "attachmentDiv%1" ).arg( node->nodeId() ) );
2873
 
  if ( attachmentDiv.isNull() ) {
2874
 
    kWarning() << "Could not find attachment div for attachment" << node->nodeId();
2875
 
    return;
2876
 
  }
2877
 
  attachmentDiv.setAttribute( "style", QString( "border:2px solid %1" )
2878
 
      .arg( cssHelper()->pgpWarnColor().name() ) );
2879
 
 
2880
 
  // Update rendering, otherwise the rendering is not updated when the user clicks on an attachment
2881
 
  // that causes scrolling and the open attachment dialog
2882
 
  doc.updateRendering();
2883
 
}
2884
 
 
2885
 
void KMReaderWin::toggleFullAddressList()
2886
 
{
2887
 
  toggleFullAddressList( "To" );
2888
 
  toggleFullAddressList( "Cc" );
2889
 
}
2890
 
 
2891
 
DOM::HTMLElement KMReaderWin::getHTMLElementById( const QString &id )
2892
 
{
2893
 
  Q_ASSERT( !id.isNull() );
2894
 
  Q_ASSERT( !id.isEmpty() );
2895
 
  DOM::Document doc = mViewer->htmlDocument();
2896
 
  return static_cast<DOM::HTMLElement>( doc.getElementById( id ) );
2897
 
}
2898
 
 
2899
 
void KMReaderWin::toggleFullAddressList( const QString &field )
2900
 
{
2901
 
  // First inject the current icon
2902
 
  DOM::HTMLElement tag = getHTMLElementById( "iconFull" + field + "AddressList" );
2903
 
  if ( tag.isNull() )
2904
 
    return;
2905
 
  Q_ASSERT( tag.tagName() == "span" );
2906
 
 
2907
 
  QString imgpath( KStandardDirs::locate( "data","kmail/pics/" ) );
2908
 
  QString urlHandle;
2909
 
  QString imgSrc;
2910
 
  bool doShow = ( field == "To" && showFullToAddressList() ) || ( field == "Cc" && showFullCcAddressList() );
2911
 
  if ( doShow ) {
2912
 
    urlHandle.append( "kmail:hideFull" + field + "AddressList" );
2913
 
    imgSrc.append( "quicklistOpened.png" );
2914
 
  } else {
2915
 
    urlHandle.append( "kmail:showFull" + field + "AddressList" );
2916
 
    imgSrc.append( "quicklistClosed.png" );
2917
 
  }
2918
 
 
2919
 
  QString link = "<span style=\"text-align: right;\"><a href=\"" + urlHandle + "\"><img src=\"" + imgpath + imgSrc + "\"/></a></span>";
2920
 
  tag.setInnerHTML( link );
2921
 
 
2922
 
  // Then show/hide the full address list
2923
 
  DOM::HTMLElement dotsTag = getHTMLElementById( "dotsFull" + field + "AddressList" );
2924
 
  Q_ASSERT( dotsTag.tagName() == "span" );
2925
 
 
2926
 
  tag = getHTMLElementById( "hiddenFull" + field + "AddressList" );
2927
 
  Q_ASSERT( tag.tagName() == "span" );
2928
 
 
2929
 
  if (doShow ) {
2930
 
    dotsTag.addCSSProperty( "display", "none" );
2931
 
    tag.removeCSSProperty( "display" );
2932
 
  } else {
2933
 
    tag.addCSSProperty( "display", "none" );
2934
 
    dotsTag.removeCSSProperty( "display" );
2935
 
  }
2936
 
}
2937
 
 
2938
 
void KMReaderWin::injectAttachments()
2939
 
{
2940
 
  // inject attachments in header view
2941
 
  // we have to do that after the otp has run so we also see encrypted parts
2942
 
  DOM::Document doc = mViewer->htmlDocument();
2943
 
  DOM::Element injectionPoint = doc.getElementById( "attachmentInjectionPoint" );
2944
 
  if ( injectionPoint.isNull() )
2945
 
    return;
2946
 
 
2947
 
  QString imgpath( KStandardDirs::locate("data","kmail/pics/") );
2948
 
  QString visibility;
2949
 
  QString urlHandle;
2950
 
  QString imgSrc;
2951
 
  if( !showAttachmentQuicklist() ) {
2952
 
    urlHandle.append( "kmail:showAttachmentQuicklist" );
2953
 
    imgSrc.append( "quicklistClosed.png" );
2954
 
  } else {
2955
 
    urlHandle.append( "kmail:hideAttachmentQuicklist" );
2956
 
    imgSrc.append( "quicklistOpened.png" );
2957
 
  }
2958
 
 
2959
 
  QColor background = KColorScheme( QPalette::Active, KColorScheme::View ).background().color();
2960
 
  QString html = renderAttachments( mRootNode, background );
2961
 
  if ( html.isEmpty() )
2962
 
    return;
2963
 
 
2964
 
  QString link;
2965
 
  if ( headerStyle() == HeaderStyle::fancy() ) {
2966
 
    link += "<div style=\"text-align: left;\"><a href=\""+urlHandle+"\"><img src=\""+imgpath+imgSrc+"\"/></a></div>";
2967
 
    html.prepend( link );
2968
 
    html.prepend( QString::fromLatin1("<div style=\"float:left;\">%1&nbsp;</div>" ).arg(i18n("Attachments:")) );
2969
 
  } else {
2970
 
    link += "<div style=\"text-align: right;\"><a href=\""+urlHandle+"\"><img src=\""+imgpath+imgSrc+"\"/></a></div>";
2971
 
    html.prepend( link );
2972
 
  }
2973
 
 
2974
 
  assert( injectionPoint.tagName() == "div" );
2975
 
  static_cast<DOM::HTMLElement>( injectionPoint ).setInnerHTML( html );
2976
 
}
2977
 
 
2978
 
static QColor nextColor( const QColor & c )
2979
 
{
2980
 
  int h, s, v;
2981
 
  c.getHsv( &h, &s, &v );
2982
 
  return QColor::fromHsv( (h + 50) % 360, qMax(s, 64), v );
2983
 
}
2984
 
 
2985
 
QString KMReaderWin::renderAttachments(partNode * node, const QColor &bgColor )
2986
 
{
2987
 
  if ( !node )
2988
 
    return QString();
2989
 
 
2990
 
  QString html;
2991
 
  if ( node->firstChild() ) {
2992
 
    QString subHtml = renderAttachments( node->firstChild(), nextColor( bgColor ) );
2993
 
    if ( !subHtml.isEmpty() ) {
2994
 
 
2995
 
      QString visibility;
2996
 
      if( !showAttachmentQuicklist() ) {
2997
 
        visibility.append( "display:none;" );
2998
 
      }
2999
 
 
3000
 
      QString margin;
3001
 
      if ( node != mRootNode || headerStyle() != HeaderStyle::enterprise() )
3002
 
        margin = "padding:2px; margin:2px; ";
3003
 
      QString align = "left";
3004
 
      if ( headerStyle() == HeaderStyle::enterprise() )
3005
 
        align = "right";
3006
 
      if ( node->msgPart().typeStr().toLower() == "message" || node == mRootNode )
3007
 
        html += QString::fromLatin1("<div style=\"background:%1; %2"
3008
 
                "vertical-align:middle; float:%3; %4\">").arg( bgColor.name() ).arg( margin )
3009
 
                                                         .arg( align ).arg( visibility );
3010
 
      html += subHtml;
3011
 
      if ( node->msgPart().typeStr().toLower() == "message" || node == mRootNode )
3012
 
        html += "</div>";
3013
 
    }
3014
 
  } else {
3015
 
    QString label, icon;
3016
 
    icon = node->msgPart().iconName( KIconLoader::Small );
3017
 
    label = node->msgPart().contentDescription();
3018
 
    if( label.isEmpty() )
3019
 
      label = node->msgPart().name().trimmed();
3020
 
    if( label.isEmpty() )
3021
 
      label = node->msgPart().fileName();
3022
 
    bool typeBlacklisted = node->msgPart().typeStr().toLower() == "multipart";
3023
 
    if ( !typeBlacklisted ) {
3024
 
      typeBlacklisted = StringUtil::isCryptoPart( node->msgPart().typeStr(), node->msgPart().subtypeStr(),
3025
 
                                                  node->msgPart().fileName() );
3026
 
    }
3027
 
    typeBlacklisted = typeBlacklisted || node == mRootNode;
3028
 
    bool firstTextChildOfEncapsulatedMsg = node->msgPart().typeStr().toLower() == "text" &&
3029
 
                                           node->msgPart().subtypeStr().toLower() == "plain" &&
3030
 
                                           node->parentNode() &&
3031
 
                                           node->parentNode()->msgPart().typeStr().toLower() == "message";
3032
 
    typeBlacklisted = typeBlacklisted || firstTextChildOfEncapsulatedMsg;
3033
 
    if ( !label.isEmpty() && !icon.isEmpty() && !typeBlacklisted ) {
3034
 
      html += "<div style=\"float:left;\">";
3035
 
      html += QString::fromLatin1( "<span style=\"white-space:nowrap; border-width: 0px; border-left-width: 5px; border-color: %1; 2px; border-left-style: solid;\">" ).arg( bgColor.name() );
3036
 
      QString fileName = writeMessagePartToTempFile( &node->msgPart(), node->nodeId() );
3037
 
      QString href = node->asHREF( "header" );
3038
 
      html += QString::fromLatin1( "<a href=\"" ) + href +
3039
 
              QString::fromLatin1( "\">" );
3040
 
      html += "<img style=\"vertical-align:middle;\" src=\"" + icon + "\"/>&nbsp;";
3041
 
      if ( headerStyle() == HeaderStyle::enterprise() ) {
3042
 
        QFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
3043
 
        QFontMetrics fm( bodyFont );
3044
 
        html += fm.elidedText( label, Qt::ElideRight, 180 );
3045
 
      } else if ( headerStyle() == HeaderStyle::fancy() ) {
3046
 
        QFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
3047
 
        QFontMetrics fm( bodyFont );
3048
 
        html += fm.elidedText( label, Qt::ElideRight, 1000 );
3049
 
      } else {
3050
 
        html += label;
3051
 
      }
3052
 
      html += "</a></span></div> ";
3053
 
    }
3054
 
  }
3055
 
 
3056
 
  html += renderAttachments( node->nextSibling(), nextColor ( bgColor ) );
3057
 
  return html;
3058
 
}
3059
 
 
3060
 
using namespace KMail::Interface;
3061
 
 
3062
 
void KMReaderWin::setBodyPartMemento( const partNode *node,
3063
 
                                      const QByteArray &which,
3064
 
                                      BodyPartMemento *memento )
3065
 
{
3066
 
  const QByteArray index = node->path() + ':' + which.toLower();
3067
 
 
3068
 
  const std::map<QByteArray,BodyPartMemento*>::iterator it =
3069
 
    mBodyPartMementoMap.lower_bound( index );
3070
 
 
3071
 
  if ( it != mBodyPartMementoMap.end() && it->first == index ) {
3072
 
    if ( memento && memento == it->second ) {
3073
 
      return;
3074
 
    }
3075
 
 
3076
 
    delete it->second;
3077
 
 
3078
 
    if ( memento ) {
3079
 
      it->second = memento;
3080
 
    } else {
3081
 
      mBodyPartMementoMap.erase( it );
3082
 
    }
3083
 
  } else {
3084
 
    if ( memento ) {
3085
 
      mBodyPartMementoMap.insert( it, std::make_pair( index, memento ) );
3086
 
    }
3087
 
  }
3088
 
 
3089
 
  if ( Observable * o = memento ? memento->asObservable() : 0 ) {
3090
 
    if ( o ) {
3091
 
      o->attach( this );
3092
 
    }
3093
 
  }
3094
 
}
3095
 
 
3096
 
BodyPartMemento *KMReaderWin::bodyPartMemento( const partNode *node,
3097
 
                                               const QByteArray &which ) const
3098
 
{
3099
 
  const QByteArray index = node->path() + ':' + which.toLower();
3100
 
  const std::map<QByteArray,BodyPartMemento*>::const_iterator it =
3101
 
    mBodyPartMementoMap.find( index );
3102
 
 
3103
 
  if ( it == mBodyPartMementoMap.end() ) {
3104
 
    return 0;
3105
 
  } else {
3106
 
    return it->second;
3107
 
  }
3108
 
}
3109
 
 
3110
 
void KMReaderWin::clearBodyPartMementos()
3111
 
{
3112
 
  for ( std::map<QByteArray,BodyPartMemento*>::const_iterator
3113
 
          it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end();
3114
 
        it != end; ++it ) {
3115
 
    delete it->second;
3116
 
  }
3117
 
  mBodyPartMementoMap.clear();
3118
 
}
3119
 
 
3120
 
bool KMReaderWin::showFullToAddressList() const
3121
 
{
3122
 
  return mShowFullToAddressList;
3123
 
}
3124
 
 
3125
 
void KMReaderWin::setShowFullToAddressList( bool showFullToAddressList )
3126
 
{
3127
 
  mShowFullToAddressList = showFullToAddressList;
3128
 
}
3129
 
 
3130
 
bool KMReaderWin::showFullCcAddressList() const
3131
 
{
3132
 
  return mShowFullCcAddressList;
3133
 
}
3134
 
 
3135
 
void KMReaderWin::setShowFullCcAddressList( bool showFullCcAddressList )
3136
 
{
3137
 
  mShowFullCcAddressList = showFullCcAddressList;
3138
 
}
 
484
 
 
485
CSSHelper* KMReaderWin::cssHelper() const
 
486
{
 
487
  return mViewer->cssHelper();
 
488
}
 
489
 
 
490
bool KMReaderWin::htmlLoadExtOverride() const
 
491
{
 
492
  return mViewer->htmlLoadExtOverride();
 
493
}
 
494
void KMReaderWin::setDecryptMessageOverwrite( bool overwrite )
 
495
{
 
496
  mViewer->setDecryptMessageOverwrite( overwrite );
 
497
}
 
498
const AttachmentStrategy * KMReaderWin::attachmentStrategy() const
 
499
{
 
500
  return mViewer->attachmentStrategy();
 
501
}
 
502
 
 
503
QString KMReaderWin::overrideEncoding() const
 
504
{
 
505
  return mViewer->overrideEncoding();
 
506
}
 
507
 
 
508
KToggleAction *KMReaderWin::toggleFixFontAction()
 
509
{
 
510
  return mViewer->toggleFixFontAction();
 
511
}
 
512
 
 
513
KAction *KMReaderWin::toggleMimePartTreeAction()
 
514
{
 
515
  return mViewer->toggleMimePartTreeAction();
 
516
}
 
517
 
 
518
KAction *KMReaderWin::selectAllAction()
 
519
{
 
520
  return mViewer->selectAllAction();
 
521
}
 
522
 
 
523
const HeaderStrategy * KMReaderWin::headerStrategy() const
 
524
{
 
525
  return mViewer->headerStrategy();
 
526
}
 
527
 
 
528
HeaderStyle * KMReaderWin::headerStyle() const
 
529
{
 
530
  return mViewer->headerStyle();
 
531
}
 
532
 
 
533
KAction *KMReaderWin::copyURLAction()
 
534
{
 
535
  return mViewer->copyURLAction();
 
536
}
 
537
 
 
538
KAction *KMReaderWin::copyAction()
 
539
{
 
540
  return mViewer->copyAction();
 
541
}
 
542
KAction *KMReaderWin::urlOpenAction()
 
543
{
 
544
  return mViewer->urlOpenAction();
 
545
}
 
546
void KMReaderWin::setPrinting(bool enable)
 
547
{
 
548
  mViewer->setPrinting( enable );
 
549
}
 
550
 
 
551
void KMReaderWin::clear(bool force )
 
552
{
 
553
  mViewer->clear( force ? Viewer::Force : Viewer::Delayed );
 
554
}
 
555
 
 
556
void KMReaderWin::setMessage( const Akonadi::Item &item, Viewer::UpdateMode updateMode)
 
557
{
 
558
  kDebug() << Q_FUNC_INFO << parentWidget();
 
559
  mViewer->setMessageItem( item, updateMode );
 
560
}
 
561
 
 
562
void KMReaderWin::setMessage( KMime::Message::Ptr message)
 
563
{
 
564
  mViewer->setMessage( message );
 
565
}
 
566
 
 
567
 
 
568
KUrl KMReaderWin::urlClicked() const
 
569
{
 
570
  return mViewer->urlClicked();
 
571
}
 
572
 
 
573
void KMReaderWin::update( bool force )
 
574
{
 
575
  mViewer->update( force ? Viewer::Force : Viewer::Delayed );
 
576
}
 
577
 
 
578
void KMReaderWin::slotUrlClicked( const Akonadi::Item & item, const KUrl & url )
 
579
{
 
580
  uint identity = 0;
 
581
  if ( item.isValid() && item.parentCollection().isValid() ) {
 
582
    QSharedPointer<FolderCollection> fd = FolderCollection::forCollection( item.parentCollection() );
 
583
    if ( fd )
 
584
      identity = fd->identity();
 
585
  }
 
586
  KMail::Util::handleClickedURL( url, identity );
 
587
}
 
588
 
 
589
void KMReaderWin::slotShowReader( KMime::Content* msgPart, bool htmlMail, const QString &encoding )
 
590
{
 
591
  KMReaderMainWin *win = new KMReaderMainWin( msgPart, htmlMail, encoding );
 
592
  win->show();
 
593
}
 
594
 
 
595
void KMReaderWin::slotShowMessage( KMime::Message::Ptr message, const QString& encoding )
 
596
{
 
597
  KMReaderMainWin *win = new KMReaderMainWin();
 
598
  win->showMessage( encoding, message );
 
599
  win->show();
 
600
}
 
601
 
 
602
void KMReaderWin::slotDeleteMessage(const Akonadi::Item& item)
 
603
{
 
604
  if ( !item.isValid() )
 
605
    return;
 
606
  KMTrashMsgCommand *command = new KMTrashMsgCommand( item.parentCollection(), item, -1 );
 
607
  command->start();
 
608
}
 
609
 
3139
610
 
3140
611
#include "kmreaderwin.moc"
3141
612