00001
00002
00003
00004
00005
00006
00007
#define DEFAULT_EDITOR_STR "kate %f"
00008
00009
00010
00011
#undef GrayScale
00012
#undef Color
00013
#include <config.h>
00014
00015
#include "kmcomposewin.h"
00016
00017
#include "kmmainwin.h"
00018
#include "kmreaderwin.h"
00019
#include "kmreadermainwin.h"
00020
#include "kmsender.h"
00021
#include "identitymanager.h"
00022
#include "identitycombo.h"
00023
#include "kmidentity.h"
00024
#include "kfileio.h"
00025
#include "kmmsgpartdlg.h"
00026
#include <kpgpblock.h>
00027
#include "kmaddrbook.h"
00028
#include "kmmsgdict.h"
00029
#include "kmfolderimap.h"
00030
#include "kmfoldermgr.h"
00031
#include "kmfoldercombobox.h"
00032
#include "kmtransport.h"
00033
#include "kmcommands.h"
00034
#include "kcursorsaver.h"
00035
#include "kmkernel.h"
00036
#include "attachmentlistview.h"
00037
using KMail::AttachmentListView;
00038
#include "dictionarycombobox.h"
00039
using KMail::DictionaryComboBox;
00040
#include "addressesdialog.h"
00041
using KPIM::AddressesDialog;
00042
#include <maillistdrag.h>
00043
using KPIM::MailListDrag;
00044
#include "recentaddresses.h"
00045
using KRecentAddress::RecentAddresses;
00046
00047
#include <cryptplugwrapperlist.h>
00048
00049
#include "klistboxdialog.h"
00050
00051
#include <kcharsets.h>
00052
#include <kcompletionbox.h>
00053
#include <kcursor.h>
00054
#include <kcombobox.h>
00055
#include <kstdaccel.h>
00056
#include <kpopupmenu.h>
00057
#include <kedittoolbar.h>
00058
#include <kkeydialog.h>
00059
#include <kdebug.h>
00060
#include <kfiledialog.h>
00061
#include <kwin.h>
00062
#include <kinputdialog.h>
00063
#include <kmessagebox.h>
00064
#include <kurldrag.h>
00065
#include <kio/scheduler.h>
00066
#include <ktempfile.h>
00067
#include <klocale.h>
00068
#include <kapplication.h>
00069
#include <kstatusbar.h>
00070
#include <kaction.h>
00071
#include <kdirwatch.h>
00072
#include <kstdguiitem.h>
00073
#include <kiconloader.h>
00074
00075
#include <kspell.h>
00076
#include <kspelldlg.h>
00077
#include <spellingfilter.h>
00078
#include <ksyntaxhighlighter.h>
00079
00080
#include <qtabdialog.h>
00081
#include <qregexp.h>
00082
#include <qbuffer.h>
00083
#include <qtooltip.h>
00084
#include <qtextcodec.h>
00085
#include <qheader.h>
00086
#include <qpopupmenu.h>
00087
00088
#include <mimelib/mimepp.h>
00089
#include <sys/stat.h>
00090
#include <sys/types.h>
00091
#include <stdlib.h>
00092
#include <unistd.h>
00093
#include <errno.h>
00094
#include <fcntl.h>
00095
#include <assert.h>
00096
00097
#include "kmcomposewin.moc"
00098
00099
00100 KMComposeWin::KMComposeWin( KMMessage *aMsg, uint
id )
00101 :
MailComposerIface(),
KMTopLevelWidget("kmail-composer#"),
00102 mMsg( 0 ),
00103 mAutoRequestMDN( false ),
00104 mId( id ), mNeverSign( false ), mNeverEncrypt( false )
00105 {
00106
if (kmkernel->xmlGuiInstance())
00107 setInstance( kmkernel->xmlGuiInstance() );
00108 mMainWidget =
new QWidget(
this);
00109
00110
00111
00112 mSelectedCryptPlug = kmkernel->cryptPlugList() ? kmkernel->cryptPlugList()->active() : 0;
00113
00114 mIdentity =
new IdentityCombo(mMainWidget);
00115 mDictionaryCombo =
new DictionaryComboBox( mMainWidget );
00116 mFcc =
new KMFolderComboBox(mMainWidget);
00117 mFcc->showOutboxFolder( FALSE );
00118 mTransport =
new QComboBox(
true, mMainWidget);
00119 mEdtFrom =
new KMLineEdit(
this,
false,mMainWidget);
00120 mEdtReplyTo =
new KMLineEdit(
this,
false,mMainWidget);
00121 mEdtTo =
new KMLineEdit(
this,
true,mMainWidget);
00122 mEdtCc =
new KMLineEdit(
this,
true,mMainWidget);
00123 mEdtBcc =
new KMLineEdit(
this,
true,mMainWidget);
00124 mEdtSubject =
new KMLineEditSpell(
this,
false,mMainWidget,
"subjectLine");
00125 mLblIdentity =
new QLabel(mMainWidget);
00126 mDictionaryLabel =
new QLabel( mMainWidget );
00127 mLblFcc =
new QLabel(mMainWidget);
00128 mLblTransport =
new QLabel(mMainWidget);
00129 mLblFrom =
new QLabel(mMainWidget);
00130 mLblReplyTo =
new QLabel(mMainWidget);
00131 mLblTo =
new QLabel(mMainWidget);
00132 mLblCc =
new QLabel(mMainWidget);
00133 mLblBcc =
new QLabel(mMainWidget);
00134 mLblSubject =
new QLabel(mMainWidget);
00135 QString sticky = i18n(
"Sticky");
00136 mBtnIdentity =
new QCheckBox(sticky,mMainWidget);
00137 mBtnFcc =
new QCheckBox(sticky,mMainWidget);
00138 mBtnTransport =
new QCheckBox(sticky,mMainWidget);
00139 mBtnTo =
new QPushButton(
"...",mMainWidget);
00140 mBtnCc =
new QPushButton(
"...",mMainWidget);
00141 mBtnBcc =
new QPushButton(
"...",mMainWidget);
00142
00143 mBtnReplyTo =
new QPushButton(
"...",mMainWidget);
00144
00145
00146 mDone =
false;
00147 mGrid = 0;
00148 mAtmListView = 0;
00149 mAtmList.setAutoDelete(TRUE);
00150 mAtmTempList.setAutoDelete(TRUE);
00151 mAtmModified = FALSE;
00152 mAutoDeleteMsg = FALSE;
00153 mFolder = 0;
00154 mAutoCharset = TRUE;
00155 mFixedFontAction = 0;
00156 mEditor =
new KMEdit( mMainWidget,
this, mDictionaryCombo->spellConfig() );
00157 mEditor->setTextFormat(Qt::PlainText);
00158 mEditor->setAcceptDrops(
true );
00159
00160 mDisableBreaking =
false;
00161 QString tip = i18n(
"Select email address(es)");
00162 QToolTip::add( mBtnTo, tip );
00163 QToolTip::add( mBtnCc, tip );
00164 QToolTip::add( mBtnReplyTo, tip );
00165
00166 mSpellCheckInProgress=FALSE;
00167
00168 setCaption( i18n(
"Composer") );
00169 setMinimumSize(200,200);
00170
00171 mBtnIdentity->setFocusPolicy(QWidget::NoFocus);
00172 mBtnFcc->setFocusPolicy(QWidget::NoFocus);
00173 mBtnTransport->setFocusPolicy(QWidget::NoFocus);
00174 mBtnTo->setFocusPolicy(QWidget::NoFocus);
00175 mBtnCc->setFocusPolicy(QWidget::NoFocus);
00176 mBtnBcc->setFocusPolicy(QWidget::NoFocus);
00177
00178 mBtnReplyTo->setFocusPolicy(QWidget::NoFocus);
00179
00180 mAtmListView =
new AttachmentListView(
this, mMainWidget,
00181
"attachment list view" );
00182 mAtmListView->setSelectionMode( QListView::Extended );
00183 mAtmListView->setFocusPolicy( QWidget::NoFocus );
00184 mAtmListView->addColumn( i18n(
"Name"), 200 );
00185 mAtmListView->addColumn( i18n(
"Size"), 80 );
00186 mAtmListView->addColumn( i18n(
"Encoding"), 120 );
00187
int atmColType = mAtmListView->addColumn( i18n(
"Type"), 120 );
00188
00189 mAtmListView->header()->setStretchEnabled(
true, atmColType );
00190 mAtmEncryptColWidth = 80;
00191 mAtmSignColWidth = 80;
00192 mAtmColEncrypt = mAtmListView->addColumn( i18n(
"Encrypt"),
00193 mAtmEncryptColWidth );
00194 mAtmColSign = mAtmListView->addColumn( i18n(
"Sign"),
00195 mAtmSignColWidth );
00196
if( mSelectedCryptPlug ) {
00197 mAtmListView->setColumnWidth( mAtmColEncrypt, mAtmEncryptColWidth );
00198 mAtmListView->setColumnWidth( mAtmColSign, mAtmSignColWidth );
00199 }
00200
else {
00201 mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
00202 mAtmListView->setColumnWidth( mAtmColSign, 0 );
00203 }
00204 mAtmListView->setAllColumnsShowFocus(
true );
00205
00206 connect( mAtmListView,
00207 SIGNAL( doubleClicked( QListViewItem* ) ),
00208 SLOT( slotAttachProperties() ) );
00209 connect( mAtmListView,
00210 SIGNAL( rightButtonPressed( QListViewItem*,
const QPoint&,
int ) ),
00211 SLOT( slotAttachPopupMenu( QListViewItem*,
const QPoint&,
int ) ) );
00212 connect( mAtmListView,
00213 SIGNAL( selectionChanged() ),
00214 SLOT( slotUpdateAttachActions() ) );
00215 mAttachMenu = 0;
00216
00217 readConfig();
00218 setupStatusBar();
00219 setupEditor();
00220 setupActions();
00221 applyMainWindowSettings(KMKernel::config(),
"Composer");
00222
00223 connect(mEdtSubject,SIGNAL(textChanged(
const QString&)),
00224 SLOT(slotUpdWinTitle(
const QString&)));
00225 connect(mBtnTo,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
00226 connect(mBtnCc,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
00227 connect(mBtnBcc,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
00228 connect(mBtnReplyTo,SIGNAL(clicked()),SLOT(slotAddrBookReplyTo()));
00229
00230 connect(mIdentity,SIGNAL(identityChanged(uint)),
00231 SLOT(slotIdentityChanged(uint)));
00232
00233 connect(mEdtTo,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00234 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00235 connect(mEdtCc,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00236 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00237 connect(mEdtBcc,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00238 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00239 connect(mEdtReplyTo,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00240 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00241 connect(mEdtFrom,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00242 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00243 connect(kmkernel->folderMgr(),SIGNAL(folderRemoved(
KMFolder*)),
00244 SLOT(slotFolderRemoved(
KMFolder*)));
00245 connect(kmkernel->imapFolderMgr(),SIGNAL(folderRemoved(
KMFolder*)),
00246 SLOT(slotFolderRemoved(
KMFolder*)));
00247 connect(kmkernel->dimapFolderMgr(),SIGNAL(folderRemoved(
KMFolder*)),
00248 SLOT(slotFolderRemoved(
KMFolder*)));
00249 connect( kmkernel, SIGNAL( configChanged() ),
00250
this, SLOT( slotConfigChanged() ) );
00251
00252 connect (mEditor, SIGNAL (spellcheck_done(
int)),
00253
this, SLOT (slotSpellcheckDone (
int)));
00254
00255 mMainWidget->resize(480,510);
00256 setCentralWidget(mMainWidget);
00257 rethinkFields();
00258
00259
if (mUseExtEditor) {
00260 mEditor->setUseExternalEditor(
true);
00261 mEditor->setExternalEditorPath(mExtEditor);
00262 }
00263
00264 mMsg = 0;
00265 mBccMsgList.setAutoDelete(
false );
00266
if (aMsg)
00267 setMsg(aMsg);
00268
00269 mEdtTo->setFocus();
00270 mErrorProcessingStructuringInfo =
00271 i18n(
"<qt><p>Structuring information returned by the Crypto plug-in "
00272
"could not be processed correctly; the plug-in might be damaged.</p>"
00273
"<p>Please contact your system administrator.</p></qt>");
00274 mErrorNoCryptPlugAndNoBuildIn =
00275 i18n(
"<p>No active Crypto Plug-In was found and the built-in OpenPGP code "
00276
"did not run successfully.</p>"
00277
"<p>You can do two things to change this:</p>"
00278
"<ul><li><em>either</em> activate a Plug-In using the "
00279
"Settings->Configure KMail->Plug-In dialog.</li>"
00280
"<li><em>or</em> specify traditional OpenPGP settings on the same dialog's "
00281
"Identity->Advanced tab.</li></ul>");
00282
00283
if(getenv(
"KMAIL_DEBUG_COMPOSER_CRYPTO") != 0){
00284 QCString cE = getenv(
"KMAIL_DEBUG_COMPOSER_CRYPTO");
00285 mDebugComposerCrypto = cE ==
"1" || cE.upper() ==
"ON" || cE.upper() ==
"TRUE";
00286 kdDebug(5006) <<
"KMAIL_DEBUG_COMPOSER_CRYPTO = TRUE" << endl;
00287 }
else{
00288 mDebugComposerCrypto =
false;
00289 kdDebug(5006) <<
"KMAIL_DEBUG_COMPOSER_CRYPTO = FALSE" << endl;
00290 }
00291 mDone =
true;
00292 }
00293
00294
00295
00296 KMComposeWin::~KMComposeWin()
00297 {
00298 writeConfig();
00299
if (mFolder && mMsg)
00300 {
00301 mAutoDeleteMsg = FALSE;
00302 mFolder->addMsg(mMsg);
00303
00304 mFolder->unGetMsg( mFolder->count() - 1 );
00305 emit messageQueuedOrDrafted();
00306 }
00307
if (mAutoDeleteMsg) {
00308
delete mMsg;
00309 mMsg = 0;
00310 }
00311 QMap<KIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.begin();
00312
while ( it != mMapAtmLoadData.end() )
00313 {
00314 KIO::Job *job = it.key();
00315 mMapAtmLoadData.remove( it );
00316 job->kill();
00317 it = mMapAtmLoadData.begin();
00318 }
00319 mBccMsgList.clear();
00320 }
00321
00322
00323
void KMComposeWin::send(
int how)
00324 {
00325
switch (how) {
00326
case 1:
00327 slotSendNow();
00328
break;
00329
default:
00330
case 0:
00331
00332
case 2:
00333 slotSendLater();
00334
break;
00335 }
00336 }
00337
00338
00339
void KMComposeWin::addAttachment(KURL url,QString )
00340 {
00341 addAttach(url);
00342 }
00343
00344
00345
void KMComposeWin::addAttachment(
const QString &name,
00346
const QCString &,
00347
const QByteArray &data,
00348
const QCString &type,
00349
const QCString &subType,
00350
const QCString ¶mAttr,
00351
const QString ¶mValue,
00352
const QCString &contDisp)
00353 {
00354
if (!data.isEmpty()) {
00355 KMMessagePart *msgPart =
new KMMessagePart;
00356 msgPart->setName(name);
00357 QValueList<int> dummy;
00358 msgPart->setBodyAndGuessCte(data, dummy,
00359 kmkernel->msgSender()->sendQuotedPrintable());
00360 msgPart->setTypeStr(type);
00361 msgPart->setSubtypeStr(subType);
00362 msgPart->setParameter(paramAttr,paramValue);
00363 msgPart->setContentDisposition(contDisp);
00364 addAttach(msgPart);
00365 }
00366 }
00367
00368
00369
void KMComposeWin::setBody(QString body)
00370 {
00371 mEditor->setText(body);
00372 }
00373
00374
00375
bool KMComposeWin::event(QEvent *e)
00376 {
00377
if (e->type() == QEvent::ApplicationPaletteChange)
00378 {
00379 readColorConfig();
00380 }
00381
return KMTopLevelWidget::event(e);
00382 }
00383
00384
00385
00386
void KMComposeWin::readColorConfig(
void)
00387 {
00388 KConfig *config = KMKernel::config();
00389 KConfigGroupSaver saver(config,
"Reader");
00390 QColor c1=QColor(kapp->palette().active().text());
00391 QColor c4=QColor(kapp->palette().active().base());
00392
00393
if (!config->readBoolEntry(
"defaultColors",TRUE)) {
00394 mForeColor = config->readColorEntry(
"ForegroundColor",&c1);
00395 mBackColor = config->readColorEntry(
"BackgroundColor",&c4);
00396 }
00397
else {
00398 mForeColor = c1;
00399 mBackColor = c4;
00400 }
00401
00402
00403 mPalette = kapp->palette();
00404 QColorGroup cgrp = mPalette.active();
00405 cgrp.setColor( QColorGroup::Base, mBackColor);
00406 cgrp.setColor( QColorGroup::Text, mForeColor);
00407 mPalette.setDisabled(cgrp);
00408 mPalette.setActive(cgrp);
00409 mPalette.setInactive(cgrp);
00410
00411 mEdtTo->setPalette(mPalette);
00412 mEdtFrom->setPalette(mPalette);
00413 mEdtCc->setPalette(mPalette);
00414 mEdtSubject->setPalette(mPalette);
00415 mEdtReplyTo->setPalette(mPalette);
00416 mEdtBcc->setPalette(mPalette);
00417 mTransport->setPalette(mPalette);
00418 mEditor->setPalette(mPalette);
00419 mFcc->setPalette(mPalette);
00420 }
00421
00422
00423
void KMComposeWin::readConfig(
void)
00424 {
00425 KConfig *config = KMKernel::config();
00426 QCString str;
00427
00428
int maxTransportItems;
00429
00430 KConfigGroupSaver saver(config,
"Composer");
00431
00432 mDefCharset = KMMessage::defaultCharset();
00433 mForceReplyCharset = config->readBoolEntry(
"force-reply-charset",
false );
00434 mAutoSign = config->readEntry(
"signature",
"auto") ==
"auto";
00435 mShowHeaders = config->readNumEntry(
"headers", HDR_STANDARD);
00436 mWordWrap = config->readBoolEntry(
"word-wrap",
true);
00437 mLineBreak = config->readNumEntry(
"break-at", 78);
00438 mBtnIdentity->setChecked(config->readBoolEntry(
"sticky-identity",
false));
00439
if (mBtnIdentity->isChecked())
00440 mId = config->readUnsignedNumEntry(
"previous-identity", mId );
00441 mBtnFcc->setChecked(config->readBoolEntry(
"sticky-fcc",
false));
00442 QString previousFcc = kmkernel->sentFolder()->idString();
00443
if (mBtnFcc->isChecked())
00444 previousFcc = config->readEntry(
"previous-fcc", previousFcc );
00445 mBtnTransport->setChecked(config->readBoolEntry(
"sticky-transport",
false));
00446 mTransportHistory = config->readListEntry(
"transport-history");
00447 QString currentTransport = config->readEntry(
"current-transport");
00448 maxTransportItems = config->readNumEntry(
"max-transport-items",10);
00449
00450
if ((mLineBreak == 0) || (mLineBreak > 78))
00451 mLineBreak = 78;
00452
if (mLineBreak < 30)
00453 mLineBreak = 30;
00454 mAutoPgpSign = config->readBoolEntry(
"pgp-auto-sign",
false);
00455 mAutoPgpEncrypt = config->readBoolEntry(
"pgp-auto-encrypt",
false);
00456 mConfirmSend = config->readBoolEntry(
"confirm-before-send",
false);
00457 mAutoRequestMDN = config->readBoolEntry(
"request-mdn",
false);
00458
00459
int mode = config->readNumEntry(
"Completion Mode",
00460 KGlobalSettings::completionMode() );
00461 mEdtFrom->setCompletionMode( (KGlobalSettings::Completion) mode );
00462 mEdtReplyTo->setCompletionMode( (KGlobalSettings::Completion) mode );
00463 mEdtTo->setCompletionMode( (KGlobalSettings::Completion) mode );
00464 mEdtCc->setCompletionMode( (KGlobalSettings::Completion) mode );
00465 mEdtBcc->setCompletionMode( (KGlobalSettings::Completion) mode );
00466
00467 readColorConfig();
00468
00469 {
00470 KConfigGroupSaver saver(config,
"General");
00471 mExtEditor = config->readPathEntry(
"external-editor", DEFAULT_EDITOR_STR);
00472 mUseExtEditor = config->readBoolEntry(
"use-external-editor", FALSE);
00473
00474
int headerCount = config->readNumEntry(
"mime-header-count", 0);
00475 mCustHeaders.clear();
00476 mCustHeaders.setAutoDelete(
true);
00477
for (
int i = 0; i < headerCount; i++) {
00478 QString thisGroup;
00479 _StringPair *thisItem =
new _StringPair;
00480 thisGroup.sprintf(
"Mime #%d", i);
00481 KConfigGroupSaver saver(config, thisGroup);
00482 thisItem->name = config->readEntry(
"name");
00483
if ((thisItem->name).length() > 0) {
00484 thisItem->value = config->readEntry(
"value");
00485 mCustHeaders.append(thisItem);
00486 }
else {
00487
delete thisItem;
00488 thisItem = 0;
00489 }
00490 }
00491 }
00492
00493 {
00494 KConfigGroupSaver saver(config,
"Fonts");
00495 mBodyFont = KGlobalSettings::generalFont();
00496 mFixedFont = KGlobalSettings::fixedFont();
00497
if (!config->readBoolEntry(
"defaultFonts",TRUE)) {
00498 mBodyFont = config->readFontEntry(
"composer-font", &mBodyFont);
00499 mFixedFont = config->readFontEntry(
"fixed-font", &mFixedFont);
00500 }
00501 slotUpdateFont();
00502 mEdtFrom->setFont(mBodyFont);
00503 mEdtReplyTo->setFont(mBodyFont);
00504 mEdtTo->setFont(mBodyFont);
00505 mEdtCc->setFont(mBodyFont);
00506 mEdtBcc->setFont(mBodyFont);
00507 mEdtSubject->setFont(mBodyFont);
00508 }
00509
00510 {
00511 KConfigGroupSaver saver(config,
"Geometry");
00512 QSize defaultSize(480,510);
00513 QSize siz = config->readSizeEntry(
"composer", &defaultSize);
00514
if (siz.width() < 200) siz.setWidth(200);
00515
if (siz.height() < 200) siz.setHeight(200);
00516 resize(siz);
00517 }
00518
00519 mIdentity->setCurrentIdentity( mId );
00520
00521 kdDebug(5006) <<
"KMComposeWin::readConfig. " << mIdentity->currentIdentityName() << endl;
00522
const KMIdentity & ident =
00523 kmkernel->identityManager()->identityForUoid( mIdentity->currentIdentity() );
00524
00525 mDictionaryCombo->setCurrentByDictionary( ident.
dictionary() );
00526
00527 mTransport->clear();
00528 mTransport->insertStringList( KMTransportInfo::availableTransports() );
00529
while (mTransportHistory.count() > (uint)maxTransportItems)
00530 mTransportHistory.remove( mTransportHistory.last() );
00531 mTransport->insertStringList( mTransportHistory );
00532
if (mBtnTransport->isChecked() && !currentTransport.isEmpty())
00533 {
00534
for (
int i = 0; i < mTransport->count(); i++)
00535
if (mTransport->text(i) == currentTransport)
00536 mTransport->setCurrentItem(i);
00537 mTransport->setEditText( currentTransport );
00538 }
00539
00540
if ( !mBtnFcc->isChecked() )
00541 {
00542 kdDebug(5006) <<
"KMComposeWin::readConfig: identity.fcc()='"
00543 << ident.
fcc() <<
"'" << endl;
00544
if ( ident.
fcc().isEmpty() )
00545 previousFcc = kmkernel->sentFolder()->idString();
00546
else
00547 previousFcc = ident.
fcc();
00548 kdDebug(5006) <<
"KMComposeWin::readConfig: previousFcc="
00549 << previousFcc << endl;
00550 }
00551
00552 setFcc( previousFcc );
00553 }
00554
00555
00556
void KMComposeWin::writeConfig(
void)
00557 {
00558 KConfig *config = KMKernel::config();
00559 QString str;
00560
00561 {
00562 KConfigGroupSaver saver(config,
"Composer");
00563 config->writeEntry(
"signature", mAutoSign?
"auto":
"manual");
00564 config->writeEntry(
"headers", mShowHeaders);
00565 config->writeEntry(
"sticky-transport", mBtnTransport->isChecked());
00566 config->writeEntry(
"sticky-identity", mBtnIdentity->isChecked());
00567 config->writeEntry(
"sticky-fcc", mBtnFcc->isChecked());
00568 config->writeEntry(
"previous-identity", mIdentity->currentIdentity() );
00569 config->writeEntry(
"current-transport", mTransport->currentText());
00570 config->writeEntry(
"previous-fcc", mFcc->getFolder()->idString() );
00571 config->writeEntry(
"autoSpellChecking",
00572 mAutoSpellCheckingAction->isChecked() );
00573 mTransportHistory.remove(mTransport->currentText());
00574
if (KMTransportInfo::availableTransports().findIndex(mTransport
00575 ->currentText()) == -1)
00576 mTransportHistory.prepend(mTransport->currentText());
00577 config->writeEntry(
"transport-history", mTransportHistory );
00578 }
00579
00580 {
00581 KConfigGroupSaver saver(config,
"Geometry");
00582 config->writeEntry(
"composer", size());
00583
00584 saveMainWindowSettings(config,
"Composer");
00585 config->sync();
00586 }
00587 }
00588
00589
00590
00591
void KMComposeWin::deadLetter(
void)
00592 {
00593
if (!mMsg)
return;
00594
00595
00596
00597
00598
bool bSaveNeverSign = mNeverSign; mNeverSign =
true;
00599
bool bSaveNeverEncrypt = mNeverEncrypt; mNeverEncrypt =
true;
00600 applyChanges(
true );
00601 mNeverSign = bSaveNeverSign;
00602 mNeverEncrypt = bSaveNeverEncrypt;
00603 QCString msgStr = mMsg->asString();
00604 QCString fname = getenv(
"HOME");
00605 fname +=
"/dead.letter.tmp";
00606
00607
00608
00609
00610
00611
int fd = open(fname, O_CREAT|O_APPEND|O_WRONLY, S_IWRITE|S_IREAD);
00612
if (fd != -1)
00613 {
00614 QCString startStr =
"From " + mMsg->fromEmail() +
" " + mMsg->dateShortStr() +
"\n";
00615 ::write(fd, startStr, startStr.length());
00616 ::write(fd, msgStr, msgStr.length());
00617 ::write(fd,
"\n", 1);
00618 ::close(fd);
00619 fprintf(stderr,
"appending message to ~/dead.letter.tmp\n");
00620 }
else {
00621 perror(
"cannot open ~/dead.letter.tmp for saving the current message");
00622 kmkernel->emergencyExit( i18n(
"cannot open ~/dead.letter.tmp for saving the current message: ") +
00623 QString::fromLocal8Bit(strerror(errno)));
00624 }
00625 }
00626
00627
00628
00629
00630
void KMComposeWin::slotView(
void)
00631 {
00632
if (!mDone)
00633
return;
00634
00635
int id;
00636
00637
00638
00639
if (!sender()->isA(
"KToggleAction"))
00640
return;
00641 KToggleAction *act = (KToggleAction *) sender();
00642
00643
if (act == mAllFieldsAction)
00644
id = 0;
00645
else if (act == mIdentityAction)
00646
id = HDR_IDENTITY;
00647
else if (act == mTransportAction)
00648
id = HDR_TRANSPORT;
00649
else if (act == mFromAction)
00650
id = HDR_FROM;
00651
else if (act == mReplyToAction)
00652
id = HDR_REPLY_TO;
00653
else if (act == mToAction)
00654
id = HDR_TO;
00655
else if (act == mCcAction)
00656
id = HDR_CC;
00657
else if (act == mBccAction)
00658
id = HDR_BCC;
00659
else if (act == mSubjectAction)
00660
id = HDR_SUBJECT;
00661
else if (act == mFccAction)
00662
id = HDR_FCC;
00663
else if ( act == mDictionaryAction )
00664
id = HDR_DICTIONARY;
00665
else
00666 {
00667
id = 0;
00668 kdDebug(5006) <<
"Something is wrong (Oh, yeah?)" << endl;
00669
return;
00670 }
00671
00672
00673
00674
00675
if (!act->isChecked())
00676 {
00677
00678
if (
id > 0) mShowHeaders = mShowHeaders & ~id;
00679
else mShowHeaders = abs(mShowHeaders);
00680 }
00681
else
00682 {
00683
00684
if (
id > 0) mShowHeaders |=
id;
00685
else mShowHeaders = -abs(mShowHeaders);
00686 }
00687 rethinkFields(
true);
00688
00689 }
00690
00691
void KMComposeWin::rethinkFields(
bool fromSlot)
00692 {
00693
00694
int mask, row, numRows;
00695
long showHeaders;
00696
00697
if (mShowHeaders < 0)
00698 showHeaders = HDR_ALL;
00699
else
00700 showHeaders = mShowHeaders;
00701
00702
for (mask=1,mNumHeaders=0; mask<=showHeaders; mask<<=1)
00703
if ((showHeaders&mask) != 0) mNumHeaders++;
00704
00705 numRows = mNumHeaders + 2;
00706
00707
delete mGrid;
00708 mGrid =
new QGridLayout(mMainWidget, numRows, 3, 4, 4);
00709 mGrid->setColStretch(0, 1);
00710 mGrid->setColStretch(1, 100);
00711 mGrid->setColStretch(2, 1);
00712 mGrid->setRowStretch(mNumHeaders, 100);
00713
00714 mEdtList.clear();
00715 row = 0;
00716 kdDebug(5006) <<
"KMComposeWin::rethinkFields" << endl;
00717
if (!fromSlot) mAllFieldsAction->setChecked(showHeaders==HDR_ALL);
00718
00719
if (!fromSlot) mIdentityAction->setChecked(abs(mShowHeaders)&HDR_IDENTITY);
00720 rethinkHeaderLine(showHeaders,HDR_IDENTITY, row, i18n(
"&Identity:"),
00721 mLblIdentity, mIdentity, mBtnIdentity);
00722
if (!fromSlot) mDictionaryAction->setChecked(abs(mShowHeaders)&HDR_DICTIONARY);
00723 rethinkHeaderLine(showHeaders,HDR_DICTIONARY, row, i18n(
"&Dictionary:"),
00724 mDictionaryLabel, mDictionaryCombo, 0 );
00725
if (!fromSlot) mFccAction->setChecked(abs(mShowHeaders)&HDR_FCC);
00726 rethinkHeaderLine(showHeaders,HDR_FCC, row, i18n(
"Se&nt-Mail folder:"),
00727 mLblFcc, mFcc, mBtnFcc);
00728
if (!fromSlot) mTransportAction->setChecked(abs(mShowHeaders)&HDR_TRANSPORT);
00729 rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row, i18n(
"Mai&l transport:"),
00730 mLblTransport, mTransport, mBtnTransport);
00731
if (!fromSlot) mFromAction->setChecked(abs(mShowHeaders)&HDR_FROM);
00732 rethinkHeaderLine(showHeaders,HDR_FROM, row, i18n(
"&From:"),
00733 mLblFrom, mEdtFrom );
00734
if (!fromSlot) mReplyToAction->setChecked(abs(mShowHeaders)&HDR_REPLY_TO);
00735 rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,i18n(
"&Reply to:"),
00736 mLblReplyTo, mEdtReplyTo, mBtnReplyTo);
00737
if (!fromSlot) mToAction->setChecked(abs(mShowHeaders)&HDR_TO);
00738 rethinkHeaderLine(showHeaders,HDR_TO, row, i18n(
"To:"),
00739 mLblTo, mEdtTo, mBtnTo);
00740
if (!fromSlot) mCcAction->setChecked(abs(mShowHeaders)&HDR_CC);
00741 rethinkHeaderLine(showHeaders,HDR_CC, row, i18n(
"&CC:"),
00742 mLblCc, mEdtCc, mBtnCc);
00743
if (!fromSlot) mBccAction->setChecked(abs(mShowHeaders)&HDR_BCC);
00744 rethinkHeaderLine(showHeaders,HDR_BCC, row, i18n(
"&BCC:"),
00745 mLblBcc, mEdtBcc, mBtnBcc);
00746
if (!fromSlot) mSubjectAction->setChecked(abs(mShowHeaders)&HDR_SUBJECT);
00747 rethinkHeaderLine(showHeaders,HDR_SUBJECT, row, i18n(
"S&ubject:"),
00748 mLblSubject, mEdtSubject);
00749 assert(row<=mNumHeaders);
00750
00751 mGrid->addMultiCellWidget(mEditor, row, mNumHeaders, 0, 2);
00752 mGrid->addMultiCellWidget(mAtmListView, mNumHeaders+1, mNumHeaders+1, 0, 2);
00753
00754
if( !mAtmList.isEmpty() )
00755 mAtmListView->show();
00756
else
00757 mAtmListView->hide();
00758 resize(this->size());
00759 repaint();
00760
00761 mGrid->activate();
00762
00763 slotUpdateAttachActions();
00764 mIdentityAction->setEnabled(!mAllFieldsAction->isChecked());
00765 mDictionaryAction->setEnabled( !mAllFieldsAction->isChecked() );
00766 mTransportAction->setEnabled(!mAllFieldsAction->isChecked());
00767 mFromAction->setEnabled(!mAllFieldsAction->isChecked());
00768 mReplyToAction->setEnabled(!mAllFieldsAction->isChecked());
00769 mToAction->setEnabled(!mAllFieldsAction->isChecked());
00770 mCcAction->setEnabled(!mAllFieldsAction->isChecked());
00771 mBccAction->setEnabled(!mAllFieldsAction->isChecked());
00772 mFccAction->setEnabled(!mAllFieldsAction->isChecked());
00773 mSubjectAction->setEnabled(!mAllFieldsAction->isChecked());
00774 }
00775
00776
00777
00778
void KMComposeWin::rethinkHeaderLine(
int aValue,
int aMask,
int& aRow,
00779
const QString &aLabelStr, QLabel* aLbl,
00780 QLineEdit* aEdt, QPushButton* aBtn)
00781 {
00782
if (aValue & aMask)
00783 {
00784 aLbl->setText(aLabelStr);
00785 aLbl->adjustSize();
00786 aLbl->resize((
int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
00787 aLbl->setMinimumSize(aLbl->size());
00788 aLbl->show();
00789 aLbl->setBuddy(aEdt);
00790 mGrid->addWidget(aLbl, aRow, 0);
00791
00792 aEdt->setBackgroundColor( mBackColor );
00793 aEdt->show();
00794 aEdt->setMinimumSize(100, aLbl->height()+2);
00795 mEdtList.append(aEdt);
00796
00797 mGrid->addWidget(aEdt, aRow, 1);
00798
if (aBtn)
00799 {
00800 mGrid->addWidget(aBtn, aRow, 2);
00801 aBtn->setFixedSize(aBtn->sizeHint().width(), aLbl->height());
00802 aBtn->show();
00803 }
00804 aRow++;
00805 }
00806
else
00807 {
00808 aLbl->hide();
00809 aEdt->hide();
00810
if (aBtn) aBtn->hide();
00811 }
00812 }
00813
00814
00815
void KMComposeWin::rethinkHeaderLine(
int aValue,
int aMask,
int& aRow,
00816
const QString &aLabelStr, QLabel* aLbl,
00817 QComboBox* aCbx, QCheckBox* aChk)
00818 {
00819
if (aValue & aMask)
00820 {
00821 aLbl->setText(aLabelStr);
00822 aLbl->adjustSize();
00823 aLbl->resize((
int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
00824 aLbl->setMinimumSize(aLbl->size());
00825 aLbl->show();
00826 aLbl->setBuddy(aCbx);
00827 mGrid->addWidget(aLbl, aRow, 0);
00828
00829
00830 aCbx->show();
00831 aCbx->setMinimumSize(100, aLbl->height()+2);
00832
00833 mGrid->addWidget(aCbx, aRow, 1);
00834
if ( aChk ) {
00835 mGrid->addWidget(aChk, aRow, 2);
00836 aChk->setFixedSize(aChk->sizeHint().width(), aLbl->height());
00837 aChk->show();
00838 }
00839 aRow++;
00840 }
00841
else
00842 {
00843 aLbl->hide();
00844 aCbx->hide();
00845
if ( aChk )
00846 aChk->hide();
00847 }
00848 }
00849
00850
00851
void KMComposeWin::setupActions(
void)
00852 {
00853
if (kmkernel->msgSender()->sendImmediate())
00854 {
00855
00856 (
void)
new KAction (i18n(
"&Send"),
"mail_send", CTRL+Key_Return,
00857
this, SLOT(slotSendNow()), actionCollection(),
00858
"send_default");
00859 (
void)
new KAction (i18n(
"&Queue"),
"queue", 0,
00860
this, SLOT(slotSendLater()),
00861 actionCollection(),
"send_alternative");
00862 }
00863
else
00864 {
00865
00866 (
void)
new KAction (i18n(
"&Queue"),
"queue",
00867 CTRL+Key_Return,
00868
this, SLOT(slotSendLater()), actionCollection(),
00869
"send_default");
00870 (
void)
new KAction (i18n(
"&Send Now"),
"mail_send", 0,
00871
this, SLOT(slotSendNow()),
00872 actionCollection(),
"send_alternative");
00873 }
00874
00875 (
void)
new KAction (i18n(
"Save in &Drafts Folder"),
"filesave", 0,
00876
this, SLOT(slotSaveDraft()),
00877 actionCollection(),
"save_in_drafts");
00878 (
void)
new KAction (i18n(
"&Insert File..."),
"fileopen", 0,
00879
this, SLOT(slotInsertFile()),
00880 actionCollection(),
"insert_file");
00881 (
void)
new KAction (i18n(
"&Address Book"),
"contents",0,
00882
this, SLOT(slotAddrBook()),
00883 actionCollection(),
"addressbook");
00884 (
void)
new KAction (i18n(
"&New Composer"),
"mail_new",
00885 KStdAccel::shortcut(KStdAccel::New),
00886
this, SLOT(slotNewComposer()),
00887 actionCollection(),
"new_composer");
00888 (
void)
new KAction (i18n(
"New Main &Window"),
"window_new", 0,
00889
this, SLOT(slotNewMailReader()),
00890 actionCollection(),
"open_mailreader");
00891
00892
00893
00894 KStdAction::print (
this, SLOT(slotPrint()), actionCollection());
00895 KStdAction::close (
this, SLOT(slotClose()), actionCollection());
00896
00897 KStdAction::undo (
this, SLOT(slotUndo()), actionCollection());
00898 KStdAction::redo (
this, SLOT(slotRedo()), actionCollection());
00899 KStdAction::cut (
this, SLOT(slotCut()), actionCollection());
00900 KStdAction::copy (
this, SLOT(slotCopy()), actionCollection());
00901 KStdAction::pasteText (
this, SLOT(slotPaste()), actionCollection());
00902 KStdAction::selectAll (
this, SLOT(slotMarkAll()), actionCollection());
00903
00904 KStdAction::find (
this, SLOT(slotFind()), actionCollection());
00905 KStdAction::replace (
this, SLOT(slotReplace()), actionCollection());
00906 KStdAction::spelling (
this, SLOT(slotSpellcheck()), actionCollection(),
"spellcheck");
00907
00908 (
void)
new KAction (i18n(
"Pa&ste as Quotation"),0,
this,SLOT( slotPasteAsQuotation()),
00909 actionCollection(),
"paste_quoted");
00910
00911 (
void)
new KAction(i18n(
"Add &Quote Characters"), 0,
this,
00912 SLOT(slotAddQuotes()), actionCollection(),
"tools_quote");
00913
00914 (
void)
new KAction(i18n(
"Re&move Quote Characters"), 0,
this,
00915 SLOT(slotRemoveQuotes()), actionCollection(),
"tools_unquote");
00916
00917
00918 (
void)
new KAction (i18n(
"Cl&ean Spaces"), 0,
this, SLOT(slotCleanSpace()),
00919 actionCollection(),
"clean_spaces");
00920
00921 mFixedFontAction =
new KToggleAction( i18n(
"Use Fi&xed Font"), 0,
this,
00922 SLOT(slotUpdateFont()), actionCollection(),
"toggle_fixedfont" );
00923
00924
00925 mUrgentAction =
new KToggleAction (i18n(
"&Urgent"), 0,
00926 actionCollection(),
00927
"urgent");
00928 mRequestMDNAction =
new KToggleAction ( i18n(
"&Request Disposition Notification"), 0,
00929 actionCollection(),
00930
"options_request_mdn");
00931 mRequestMDNAction->setChecked(mAutoRequestMDN);
00932
00933 mEncodingAction =
new KSelectAction( i18n(
"Se&t Encoding" ),
"charset",
00934 0,
this, SLOT(slotSetCharset() ),
00935 actionCollection(),
"charsets" );
00936 mWordWrapAction =
new KToggleAction (i18n(
"&Wordwrap"), 0,
00937 actionCollection(),
"wordwrap");
00938 mWordWrapAction->setChecked(mWordWrap);
00939 connect(mWordWrapAction, SIGNAL(toggled(
bool)), SLOT(slotWordWrapToggled(
bool)));
00940
00941 mAutoSpellCheckingAction =
00942
new KToggleAction( i18n(
"&Automatic Spellchecking" ),
"spellcheck", 0,
00943 actionCollection(),
"options_auto_spellchecking" );
00944 KConfigGroup composerConfig( KMKernel::config(),
"Composer" );
00945
const bool spellChecking =
00946 composerConfig.readBoolEntry(
"autoSpellChecking",
true );
00947 mAutoSpellCheckingAction->setEnabled( !mUseExtEditor );
00948 mAutoSpellCheckingAction->setChecked( !mUseExtEditor && spellChecking );
00949 mEditor->slotAutoSpellCheckingToggled( !mUseExtEditor && spellChecking );
00950 connect( mAutoSpellCheckingAction, SIGNAL( toggled(
bool ) ),
00951 mEditor, SLOT( slotAutoSpellCheckingToggled(
bool ) ) );
00952
00953 QStringList encodings = KMMsgBase::supportedEncodings(TRUE);
00954 encodings.prepend( i18n(
"Auto-Detect"));
00955 mEncodingAction->setItems( encodings );
00956 mEncodingAction->setCurrentItem( -1 );
00957
00958
00959 mAllFieldsAction =
new KToggleAction (i18n(
"&All Fields"), 0,
this,
00960 SLOT(slotView()),
00961 actionCollection(),
"show_all_fields");
00962 mIdentityAction =
new KToggleAction (i18n(
"&Identity"), 0,
this,
00963 SLOT(slotView()),
00964 actionCollection(),
"show_identity");
00965 mDictionaryAction =
new KToggleAction (i18n(
"&Dictionary"), 0,
this,
00966 SLOT(slotView()),
00967 actionCollection(),
"show_dictionary");
00968 mFccAction =
new KToggleAction (i18n(
"Sent-Mail F&older"), 0,
this,
00969 SLOT(slotView()),
00970 actionCollection(),
"show_fcc");
00971 mTransportAction =
new KToggleAction (i18n(
"&Mail Transport"), 0,
this,
00972 SLOT(slotView()),
00973 actionCollection(),
"show_transport");
00974 mFromAction =
new KToggleAction (i18n(
"&From"), 0,
this,
00975 SLOT(slotView()),
00976 actionCollection(),
"show_from");
00977 mReplyToAction =
new KToggleAction (i18n(
"&Reply To"), 0,
this,
00978 SLOT(slotView()),
00979 actionCollection(),
"show_reply_to");
00980 mToAction =
new KToggleAction (i18n(
"&To"), 0,
this,
00981 SLOT(slotView()),
00982 actionCollection(),
"show_to");
00983 mCcAction =
new KToggleAction (i18n(
"&CC"), 0,
this,
00984 SLOT(slotView()),
00985 actionCollection(),
"show_cc");
00986 mBccAction =
new KToggleAction (i18n(
"&BCC"), 0,
this,
00987 SLOT(slotView()),
00988 actionCollection(),
"show_bcc");
00989 mSubjectAction =
new KToggleAction (i18n(
"&Subject"), 0,
this,
00990 SLOT(slotView()),
00991 actionCollection(),
"show_subject");
00992
00993
00994 (
void)
new KAction (i18n(
"Append S&ignature"), 0,
this,
00995 SLOT(slotAppendSignature()),
00996 actionCollection(),
"append_signature");
00997 mAttachPK =
new KAction (i18n(
"Attach &Public Key..."), 0,
this,
00998 SLOT(slotInsertPublicKey()),
00999 actionCollection(),
"attach_public_key");
01000 mAttachMPK =
new KAction (i18n(
"Attach &My Public Key"), 0,
this,
01001 SLOT(slotInsertMyPublicKey()),
01002 actionCollection(),
"attach_my_public_key");
01003 (
void)
new KAction (i18n(
"&Attach File..."),
"attach",
01004 0,
this, SLOT(slotAttachFile()),
01005 actionCollection(),
"attach");
01006 mAttachRemoveAction =
new KAction (i18n(
"&Remove Attachment"), 0,
this,
01007 SLOT(slotAttachRemove()),
01008 actionCollection(),
"remove");
01009 mAttachSaveAction =
new KAction (i18n(
"&Save Attachment As..."),
"filesave",0,
01010
this, SLOT(slotAttachSave()),
01011 actionCollection(),
"attach_save");
01012 mAttachPropertiesAction =
new KAction (i18n(
"Attachment Pr&operties..."), 0,
this,
01013 SLOT(slotAttachProperties()),
01014 actionCollection(),
"attach_properties");
01015
01016 createStandardStatusBarAction();
01017 setStandardToolBarMenuEnabled(
true);
01018
01019 KStdAction::keyBindings(
this, SLOT(slotEditKeys()), actionCollection());
01020 KStdAction::configureToolbars(
this, SLOT(slotEditToolbars()), actionCollection());
01021 KStdAction::preferences(kmkernel, SLOT(slotShowConfigurationDialog()), actionCollection());
01022
01023 (
void)
new KAction (i18n(
"&Spellchecker..."), 0,
this, SLOT(slotSpellcheckConfig()),
01024 actionCollection(),
"setup_spellchecker");
01025
01026 mEncryptAction =
new KToggleAction (i18n(
"&Encrypt Message"),
01027
"decrypted", 0,
01028 actionCollection(),
"encrypt_message");
01029 mSignAction =
new KToggleAction (i18n(
"&Sign Message"),
01030
"signature", 0,
01031 actionCollection(),
"sign_message");
01032
01033
const KMIdentity & ident =
01034 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
01035 QCString pgpUserId = ident.
pgpIdentity();
01036 mLastIdentityHasOpenPgpKey = !pgpUserId.isEmpty();
01037
01038 mLastEncryptActionState =
01039 ( mSelectedCryptPlug && EncryptEmail_EncryptAll == mSelectedCryptPlug->encryptEmail() );
01040 mLastSignActionState =
01041 ( (!mSelectedCryptPlug && mAutoPgpSign)
01042 || ( mSelectedCryptPlug && SignEmail_SignAll == mSelectedCryptPlug->signEmail()) );
01043
01044
01045
01046 mAttachPK->setEnabled(Kpgp::Module::getKpgp()->usePGP());
01047
01048
01049
01050 mAttachMPK->setEnabled( Kpgp::Module::getKpgp()->usePGP() &&
01051 !pgpUserId.isEmpty() );
01052
01053
if ( !mSelectedCryptPlug && !Kpgp::Module::getKpgp()->usePGP() ) {
01054 mEncryptAction->setEnabled(
false );
01055 setEncryption(
false );
01056 mSignAction->setEnabled(
false );
01057 setSigning(
false );
01058 }
01059
else if ( !mSelectedCryptPlug && pgpUserId.isEmpty() ) {
01060 setEncryption(
false );
01061 setSigning(
false );
01062 }
01063
else {
01064 setEncryption( mLastEncryptActionState );
01065 setSigning( mLastSignActionState );
01066 }
01067
01068 connect(mEncryptAction, SIGNAL(toggled(
bool)),
01069 SLOT(slotEncryptToggled(
bool )));
01070 connect(mSignAction, SIGNAL(toggled(
bool)),
01071 SLOT(slotSignToggled(
bool )));
01072
01073
if( kmkernel->cryptPlugList() && kmkernel->cryptPlugList()->count() ){
01074 QStringList lst;
01075 lst << i18n(
"inline OpenPGP (built-in)" );
01076 CryptPlugWrapper* current;
01077 QPtrListIterator<CryptPlugWrapper> it( *kmkernel->cryptPlugList() );
01078
int idx=0;
01079
int i=1;
01080
while( ( current = it.current() ) ) {
01081 lst << i18n(
"%1 (plugin)").arg(current->displayName());
01082
if( mSelectedCryptPlug == current )
01083 idx = i;
01084 ++it;
01085 ++i;
01086 }
01087
01088 mCryptoModuleAction =
new KSelectAction( i18n(
"Select &Crypto Module" ),
01089 0,
01090
this, SLOT( slotSelectCryptoModule() ),
01091 actionCollection(),
01092
"options_select_crypto" );
01093 mCryptoModuleAction->setItems( lst );
01094 mCryptoModuleAction->setCurrentItem( idx );
01095 }
01096
01097 createGUI(
"kmcomposerui.rc");
01098 }
01099
01100
01101
void KMComposeWin::setupStatusBar(
void)
01102 {
01103 statusBar()->insertItem(
"", 0, 1);
01104 statusBar()->setItemAlignment(0, AlignLeft | AlignVCenter);
01105
01106 statusBar()->insertItem(i18n(
" Column: %1 ").arg(
" "),2,0,
true);
01107 statusBar()->insertItem(i18n(
" Line: %1 ").arg(
" "),1,0,
true);
01108 }
01109
01110
01111
01112
void KMComposeWin::updateCursorPosition()
01113 {
01114
int col,line;
01115 QString temp;
01116 line = mEditor->currentLine();
01117 col = mEditor->currentColumn();
01118 temp = i18n(
" Line: %1 ").arg(line+1);
01119 statusBar()->changeItem(temp,1);
01120 temp = i18n(
" Column: %1 ").arg(col+1);
01121 statusBar()->changeItem(temp,2);
01122 }
01123
01124
01125
01126
void KMComposeWin::setupEditor(
void)
01127 {
01128
01129 mEditor->setModified(FALSE);
01130 QFontMetrics fm(mBodyFont);
01131 mEditor->setTabStopWidth(fm.width(QChar(
' ')) * 8);
01132
01133
01134
if (mWordWrap)
01135 {
01136 mEditor->setWordWrap( QMultiLineEdit::FixedColumnWidth );
01137 mEditor->setWrapColumnOrWidth(mLineBreak);
01138 }
01139
else
01140 {
01141 mEditor->setWordWrap( QMultiLineEdit::NoWrap );
01142 }
01143
01144
01145 slotUpdateFont();
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168 updateCursorPosition();
01169 connect(mEditor,SIGNAL(CursorPositionChanged()),SLOT(updateCursorPosition()));
01170 }
01171
01172
01173
01174
void KMComposeWin::verifyWordWrapLengthIsAdequate(
const QString &body)
01175 {
01176
int maxLineLength = 0;
01177
int curPos;
01178
int oldPos = 0;
01179
if (mEditor->QMultiLineEdit::wordWrap() == QMultiLineEdit::FixedColumnWidth) {
01180
for (curPos = 0; curPos < (
int)body.length(); ++curPos)
01181
if (body[curPos] ==
'\n') {
01182
if ((curPos - oldPos) > maxLineLength)
01183 maxLineLength = curPos - oldPos;
01184 oldPos = curPos;
01185 }
01186
if ((curPos - oldPos) > maxLineLength)
01187 maxLineLength = curPos - oldPos;
01188
if (mEditor->wrapColumnOrWidth() < maxLineLength)
01189 mEditor->setWrapColumnOrWidth(maxLineLength);
01190 }
01191 }
01192
01193
01194
void KMComposeWin::decryptOrStripOffCleartextSignature( QCString& body )
01195 {
01196 QPtrList<Kpgp::Block> pgpBlocks;
01197 QStrList nonPgpBlocks;
01198
if( Kpgp::Module::prepareMessageForDecryption( body,
01199 pgpBlocks, nonPgpBlocks ) )
01200 {
01201
01202
01203
if( pgpBlocks.count() == 1 )
01204 {
01205 Kpgp::Block* block = pgpBlocks.first();
01206
if( ( block->type() == Kpgp::PgpMessageBlock ) ||
01207 ( block->type() == Kpgp::ClearsignedBlock ) )
01208 {
01209
if( block->type() == Kpgp::PgpMessageBlock )
01210
01211 block->decrypt();
01212
else
01213
01214 block->verify();
01215
01216 body = nonPgpBlocks.first()
01217 + block->text()
01218 + nonPgpBlocks.last();
01219 }
01220 }
01221 }
01222 }
01223
01224
01225
void KMComposeWin::setMsg(KMMessage* newMsg,
bool mayAutoSign,
01226
bool allowDecryption,
bool isModified)
01227 {
01228 KMMessagePart bodyPart, *msgPart;
01229
int i, num;
01230
01231
01232
if(!newMsg)
01233 {
01234 kdDebug(5006) <<
"KMComposeWin::setMsg() : newMsg == 0!\n" << endl;
01235
return;
01236 }
01237 mMsg = newMsg;
01238
01239 mEdtTo->setText(mMsg->to());
01240 mEdtFrom->setText(mMsg->from());
01241 mEdtCc->setText(mMsg->cc());
01242 mEdtSubject->setText(mMsg->subject());
01243 mEdtReplyTo->setText(mMsg->replyTo());
01244 mEdtBcc->setText(mMsg->bcc());
01245
01246
if (!mBtnIdentity->isChecked() && !newMsg->headerField(
"X-KMail-Identity").isEmpty())
01247 mId = newMsg->headerField(
"X-KMail-Identity").stripWhiteSpace().toUInt();
01248
01249
01250
01251
if ( !mBtnIdentity->isChecked() ) {
01252 disconnect(mIdentity,SIGNAL(identityChanged(uint)),
01253
this, SLOT(slotIdentityChanged(uint)));
01254 }
01255 mIdentity->setCurrentIdentity( mId );
01256
if ( !mBtnIdentity->isChecked() ) {
01257 connect(mIdentity,SIGNAL(identityChanged(uint)),
01258
this, SLOT(slotIdentityChanged(uint)));
01259 }
01260
else {
01261
01262
01263
01264 slotIdentityChanged( mId );
01265 }
01266
01267
IdentityManager * im = kmkernel->identityManager();
01268
01269
const KMIdentity & ident = im->
identityForUoid( mIdentity->currentIdentity() );
01270
01271 mOldSigText = ident.
signatureText();
01272
01273
01274
01275 QString mdnAddr = newMsg->headerField(
"Disposition-Notification-To");
01276 mRequestMDNAction->setChecked( ( !mdnAddr.isEmpty() &&
01277 im->
thatIsMe( mdnAddr ) ) || mAutoRequestMDN );
01278
01279
01280 mUrgentAction->setChecked( newMsg->isUrgent() );
01281
01282
01283
switch ( mMsg->encryptionState() ) {
01284
case KMMsgFullyEncrypted:
01285
case KMMsgPartiallyEncrypted:
01286 mLastEncryptActionState =
true;
01287
break;
01288
case KMMsgNotEncrypted:
01289 mLastEncryptActionState =
false;
01290
break;
01291
default:
01292
break;
01293 }
01294
01295
01296
switch ( mMsg->signatureState() ) {
01297
case KMMsgFullySigned:
01298
case KMMsgPartiallySigned:
01299 mLastSignActionState =
true;
01300
break;
01301
case KMMsgNotSigned:
01302 mLastSignActionState =
false;
01303
break;
01304
default:
01305
break;
01306 }
01307
01308
01309 QCString pgpUserId = ident.
pgpIdentity();
01310 mLastIdentityHasOpenPgpKey = !pgpUserId.isEmpty();
01311
01312
if ( mSelectedCryptPlug || Kpgp::Module::getKpgp()->usePGP() ) {
01313
if ( !mSelectedCryptPlug && pgpUserId.isEmpty() ) {
01314 setEncryption(
false );
01315 setSigning(
false );
01316 }
01317
else {
01318 setEncryption( mLastEncryptActionState );
01319 setSigning( mLastSignActionState );
01320 }
01321 }
01322
01323
01324
01325 mAttachMPK->setEnabled( Kpgp::Module::getKpgp()->usePGP() &&
01326 !pgpUserId.isEmpty() );
01327
01328 QString transport = newMsg->headerField(
"X-KMail-Transport");
01329
if (!mBtnTransport->isChecked() && !transport.isEmpty())
01330 {
01331
for (
int i = 0; i < mTransport->count(); i++)
01332
if (mTransport->text(i) == transport)
01333 mTransport->setCurrentItem(i);
01334 mTransport->setEditText( transport );
01335 }
01336
01337
if (!mBtnFcc->isChecked())
01338 {
01339
if (!mMsg->fcc().isEmpty())
01340 setFcc(mMsg->fcc());
01341
else
01342 setFcc(ident.
fcc());
01343 }
01344
01345 mDictionaryCombo->setCurrentByDictionary( ident.
dictionary() );
01346
01347 num = mMsg->numBodyParts();
01348
01349
if (num > 0)
01350 {
01351 QCString bodyDecoded;
01352 mMsg->bodyPart(0, &bodyPart);
01353
01354
int firstAttachment = (bodyPart.typeStr().lower() ==
"text") ? 1 : 0;
01355
if (firstAttachment)
01356 {
01357 mCharset = bodyPart.charset();
01358
if ( mCharset.isEmpty() || mCharset ==
"default" )
01359 mCharset = mDefCharset;
01360
01361 bodyDecoded = bodyPart.bodyDecoded();
01362
01363
if( allowDecryption )
01364 decryptOrStripOffCleartextSignature( bodyDecoded );
01365
01366
01367
01368
01369
01370
01371
01372
const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
01373
if (codec)
01374 mEditor->setText(codec->toUnicode(bodyDecoded));
01375
else
01376 mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
01377 mEditor->insertLine(
"\n", -1);
01378 }
else mEditor->setText(
"");
01379
for(i=firstAttachment; i<num; i++)
01380 {
01381 msgPart =
new KMMessagePart;
01382 mMsg->bodyPart(i, msgPart);
01383 QCString mimeType = msgPart->typeStr().lower() +
'/'
01384 + msgPart->subtypeStr().lower();
01385
01386
01387
if( mimeType !=
"application/pgp-signature" ) {
01388 addAttach(msgPart);
01389 }
01390 }
01391 }
else{
01392 mCharset=mMsg->charset();
01393
if ( mCharset.isEmpty() || mCharset ==
"default" )
01394 mCharset = mDefCharset;
01395
01396 QCString bodyDecoded = mMsg->bodyDecoded();
01397
01398
if( allowDecryption )
01399 decryptOrStripOffCleartextSignature( bodyDecoded );
01400
01401
const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
01402
if (codec) {
01403 mEditor->setText(codec->toUnicode(bodyDecoded));
01404 }
else
01405 mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
01406 }
01407
01408 setCharset(mCharset);
01409
01410
if( mAutoSign && mayAutoSign ) {
01411
01412
01413
01414
01415
01416
01417 QTimer::singleShot( 0,
this, SLOT(slotAppendSignature()) );
01418 }
else {
01419 kmkernel->dumpDeadLetters();
01420 }
01421 mEditor->setModified(isModified);
01422 }
01423
01424
01425
01426
void KMComposeWin::setFcc(
const QString &idString )
01427 {
01428
01429
KMFolder *folder = kmkernel->folderMgr()->findIdString( idString );
01430
if ( !folder )
01431 folder = kmkernel->imapFolderMgr()->findIdString( idString );
01432
if ( !folder )
01433 folder = kmkernel->dimapFolderMgr()->findIdString( idString );
01434
if ( folder )
01435 mFcc->setFolder( idString );
01436
else
01437 mFcc->setFolder( kmkernel->sentFolder() );
01438 }
01439
01440
01441
01442
bool KMComposeWin::queryClose ()
01443 {
01444
if ( !mEditor->checkExternalEditorFinished() )
01445
return false;
01446
if (kmkernel->shuttingDown() || kapp->sessionSaving())
01447
return true;
01448
01449
if(mEditor->isModified() || mEdtFrom->edited() || mEdtReplyTo->edited() ||
01450 mEdtTo->edited() || mEdtCc->edited() || mEdtBcc->edited() ||
01451 mEdtSubject->edited() || mAtmModified ||
01452 (mTransport->lineEdit() && mTransport->lineEdit()->edited()))
01453 {
01454
const int rc = KMessageBox::warningYesNoCancel(
this,
01455 i18n(
"Do you want to discard the message or save it for later?"),
01456 i18n(
"Discard or Save Message"),
01457 i18n(
"&Save as Draft"),
01458 KStdGuiItem::discard() );
01459
if (rc == KMessageBox::Cancel)
01460
return false;
01461
else if (rc == KMessageBox::Yes)
01462
return slotSaveDraft();
01463 }
01464
return true;
01465 }
01466
01467
01468
bool KMComposeWin::userForgotAttachment()
01469 {
01470 KConfigGroup composer( KMKernel::config(),
"Composer" );
01471
bool checkForForgottenAttachments =
01472 composer.readBoolEntry(
"showForgottenAttachmentWarning",
true );
01473
01474
if ( !checkForForgottenAttachments || ( mAtmList.count() > 0 ) )
01475
return false;
01476
01477
01478 QStringList attachWordsList =
01479 composer.readListEntry(
"attachment-keywords" );
01480
01481
if ( attachWordsList.isEmpty() ) {
01482
01483 attachWordsList << QString::fromLatin1(
"attachment")
01484 << QString::fromLatin1(
"attached");
01485
if ( QString::fromLatin1(
"attachment") != i18n(
"attachment") )
01486 attachWordsList << i18n(
"attachment");
01487
if ( QString::fromLatin1(
"attached") != i18n(
"attached") )
01488 attachWordsList << i18n(
"attached");
01489 }
01490
01491 QRegExp rx ( QString::fromLatin1(
"\\b") +
01492 attachWordsList.join(
"\\b|\\b") +
01493 QString::fromLatin1(
"\\b") );
01494 rx.setCaseSensitive(
false );
01495
01496
bool gotMatch =
false;
01497
01498
01499
01500 QString subj = mEdtSubject->text();
01501 gotMatch = ( KMMessage::stripOffPrefixes( subj ) == subj )
01502 && ( rx.search( subj ) >= 0 );
01503
01504
if ( !gotMatch ) {
01505
01506
01507 QRegExp quotationRx (
"^([ \\t]*([|>:}#]|[A-Za-z]+>))+");
01508
for (
int i = 0; i < mEditor->numLines(); ++i ) {
01509 QString line = mEditor->textLine( i );
01510 gotMatch = ( quotationRx.search( line ) < 0 )
01511 && ( rx.search( line ) >= 0 );
01512
if ( gotMatch )
01513
break;
01514 }
01515 }
01516
01517
if ( !gotMatch )
01518
return false;
01519
01520
int rc = KMessageBox::warningYesNoCancel(
this,
01521 i18n(
"The message you have composed seems to refer to an "
01522
"attached file but you have not attached anything.\n"
01523
"Do you want to attach a file to your message?"),
01524 i18n(
"File Attachment Reminder"),
01525 i18n(
"&Attach file..."),
01526 i18n(
"&Send as is") );
01527
if ( rc == KMessageBox::Cancel )
01528
return true;
01529
if ( rc == KMessageBox::Yes ) {
01530 slotAttachFile();
01531
01532
return true;
01533 }
01534
return false;
01535 }
01536
01537
01538
bool KMComposeWin::applyChanges(
bool backgroundMode )
01539 {
01540 QString str, atmntStr;
01541 QString temp, replyAddr;
01542
01543
01544
if(!mMsg)
01545 {
01546 kdDebug(5006) <<
"KMComposeWin::applyChanges() : mMsg == 0!\n" << endl;
01547
return FALSE;
01548 }
01549
01550 mBccMsgList.clear();
01551
01552
if (mAutoCharset) {
01553 QCString charset = KMMsgBase::autoDetectCharset(mCharset, KMMessage::preferredCharsets(), mEditor->text());
01554
if (charset.isEmpty())
01555 {
01556 KMessageBox::sorry(
this,
01557 i18n(
"No suitable encoding could be found for your message.\n"
01558
"Please set an encoding using the 'Options' menu."));
01559
return false;
01560 }
01561 mCharset = charset;
01562 }
01563 mMsg->setCharset(mCharset);
01564
01565
01566 mMsg->setTo(to());
01567 mMsg->setFrom(from());
01568 mMsg->setCc(cc());
01569 mMsg->setSubject(subject());
01570 mMsg->setReplyTo(replyTo());
01571 mMsg->setBcc(bcc());
01572
01573
const KMIdentity &
id
01574 = kmkernel->identityManager()->identityForUoid( mIdentity->currentIdentity() );
01575 kdDebug(5006) <<
"\n\n\n\nKMComposeWin::applyChanges: " << mFcc->currentText() <<
"=="
01576 <<
id.fcc() <<
"?" << endl;
01577
01578
KMFolder *f = mFcc->getFolder();
01579 assert( f != 0 );
01580
if ( f->
idString() ==
id.fcc() )
01581 mMsg->removeHeaderField(
"X-KMail-Fcc");
01582
else
01583 mMsg->setFcc( f->
idString() );
01584
01585
01586 mMsg->setDrafts(
id.drafts() );
01587
01588
if (
id.isDefault())
01589 mMsg->removeHeaderField(
"X-KMail-Identity");
01590
else mMsg->setHeaderField(
"X-KMail-Identity", QString::number(
id.uoid() ));
01591
01592
if (!replyTo().isEmpty()) replyAddr = replyTo();
01593
else replyAddr = from();
01594
01595
if (mRequestMDNAction->isChecked())
01596 mMsg->setHeaderField(
"Disposition-Notification-To", replyAddr);
01597
else
01598 mMsg->removeHeaderField(
"Disposition-Notification-To");
01599
01600
if (mUrgentAction->isChecked()) {
01601 mMsg->setHeaderField(
"X-PRIORITY",
"2 (High)");
01602 mMsg->setHeaderField(
"Priority",
"urgent");
01603 }
else {
01604 mMsg->removeHeaderField(
"X-PRIORITY");
01605 mMsg->removeHeaderField(
"Priority");
01606 }
01607
01608 _StringPair *pCH;
01609
for (pCH = mCustHeaders.first();
01610 pCH != 0;
01611 pCH = mCustHeaders.next()) {
01612 mMsg->setHeaderField(KMMsgBase::toUsAscii(pCH->name), pCH->value);
01613 }
01614
01615
01616
01617
01618
01619 mBcc = mMsg->bcc();
01620
01621
bool doSign = mSignAction->isChecked() && !mNeverSign;
01622
bool doEncrypt = mEncryptAction->isChecked() && !mNeverEncrypt;
01623
01624
01625
const KMIdentity & ident =
01626 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
01627 QCString pgpUserId = ident.
pgpIdentity();
01628
01629
01630
bool doSignCompletely = doSign;
01631
bool doEncryptCompletely = doEncrypt;
01632
bool doEncryptPartially = doEncrypt;
01633
if( mSelectedCryptPlug && ( !mAtmList.isEmpty() ) ) {
01634
int idx=0;
01635 KMMessagePart *attachPart;
01636
for( attachPart = mAtmList.first();
01637 attachPart;
01638 attachPart=mAtmList.next(), ++idx ) {
01639
if( encryptFlagOfAttachment( idx ) ) {
01640 doEncryptPartially =
true;
01641 }
01642
else {
01643 doEncryptCompletely =
false;
01644 }
01645
if( !signFlagOfAttachment( idx ) )
01646 doSignCompletely =
false;
01647 }
01648 }
01649
01650
bool bOk =
true;
01651
01652
if( !doSignCompletely ) {
01653
if( mSelectedCryptPlug ) {
01654
01655
if( mSelectedCryptPlug->warnSendUnsigned() && !mNeverSign ) {
01656
int ret =
01657 KMessageBox::warningYesNoCancel(
this,
01658 QString(
"<qt><b>"
01659 + i18n(
"Warning:")
01660 +
"</b><br>"
01661 + ((doSign && !doSignCompletely)
01662 ? i18n(
"You specified not to sign some parts of this message, but"
01663
" you wanted to be warned not to send unsigned messages!")
01664 : i18n(
"You specified not to sign this message, but"
01665
" you wanted to be warned not to send unsigned messages!") )
01666 +
"<br> <br><b>"
01667 + i18n(
"Sign all parts of this message?")
01668 +
"</b></qt>" ),
01669 i18n(
"Signature Warning"),
01670 KGuiItem( i18n(
"&Sign All Parts") ),
01671 KGuiItem( i18n(
"Send &as is") ) );
01672
if( ret == KMessageBox::Cancel )
01673 bOk =
false;
01674
else if( ret == KMessageBox::Yes ) {
01675 doSign =
true;
01676 doSignCompletely =
true;
01677 }
01678 }
01679 }
else {
01680
01681
01682 }
01683 }
01684
01685
if( bOk ) {
01686
if( mNeverEncrypt )
01687 doEncrypt =
false;
01688
else {
01689
01690
bool bEncryptToSelf = mSelectedCryptPlug
01691 ? mSelectedCryptPlug->alwaysEncryptToSelf()
01692 : Kpgp::Module::getKpgp()->encryptToSelf();
01693
01694
bool bEncryptionPossible = !bEncryptToSelf || !pgpUserId.isEmpty();
01695
01696
bool bUsingOpenPgp = !mSelectedCryptPlug || ( mSelectedCryptPlug &&
01697 ( -1 != mSelectedCryptPlug->libName().find(
"openpgp" ) ) );
01698
01699
01700
01701
01702
01703
if( mAutoPgpEncrypt && bEncryptionPossible && bUsingOpenPgp &&
01704 !doEncryptPartially ) {
01705
01706
01707 QString _to = to().simplifyWhiteSpace();
01708
if( !cc().isEmpty() ) {
01709
if( !_to.endsWith(
",") )
01710 _to +=
",";
01711 _to += cc().simplifyWhiteSpace();
01712 }
01713
if( !mBcc.isEmpty() ) {
01714
if( !_to.endsWith(
",") )
01715 _to +=
",";
01716 _to += mBcc.simplifyWhiteSpace();
01717 }
01718 QStringList allRecipients = KMMessage::splitEmailAddrList(_to);
01719
01720 Kpgp::Module *pgp = Kpgp::Module::getKpgp();
01721
int status = pgp->encryptionPossible( allRecipients );
01722
if( 1 == status ) {
01723
01724 doEncrypt =
true;
01725 doEncryptCompletely =
true;
01726 }
01727
else if( 2 == status ) {
01728
01729
KCursorSaver idle(KBusyPtr::idle());
01730
int ret;
01731
if( doSign )
01732 ret = KMessageBox::questionYesNoCancel(
this,
01733 i18n(
"<qt><p>You have a trusted OpenPGP key for every "
01734
"recipient of this message and the message will "
01735
"be signed.</p>"
01736
"<p>Should this message also be "
01737
"encrypted?</p></qt>"),
01738 i18n(
"Encrypt Message?"),
01739 KGuiItem( i18n(
"Sign && &Encrypt") ),
01740 KGuiItem( i18n(
"&Sign Only") ) );
01741
else
01742 ret = KMessageBox::questionYesNoCancel(
this,
01743 i18n(
"<qt><p>You have a trusted OpenPGP key for every "
01744
"recipient of this message.</p>"
01745
"<p>Should this message be encrypted?</p></qt>"),
01746 i18n(
"Encrypt Message?"),
01747 KGuiItem( i18n(
"&Encrypt") ),
01748 KGuiItem( i18n(
"&Don't Encrypt") ) );
01749
if( KMessageBox::Cancel == ret )
01750
return false;
01751
else if( KMessageBox::Yes == ret ) {
01752
01753 doEncrypt =
true;
01754 doEncryptCompletely =
true;
01755 }
01756 }
01757
else if( status == -1 )
01758 {
01759
01760
KCursorSaver idle(KBusyPtr::idle());
01761
int ret =
01762 KMessageBox::warningYesNoCancel(
this,
01763 i18n(
"<qt><p>There are conflicting encryption "
01764
"preferences!</p>"
01765
"<p>Should this message be encrypted?</p></qt>"),
01766 i18n(
"Encrypt Message?"),
01767 KGuiItem( i18n(
"&Encrypt") ),
01768 KGuiItem( i18n(
"&Don't Encrypt") ) );
01769
if( KMessageBox::Cancel == ret )
01770 bOk =
false;
01771
else if( KMessageBox::Yes == ret ) {
01772
01773 doEncrypt =
true;
01774 doEncryptCompletely =
true;
01775 }
01776 }
01777 }
01778
else if( !doEncryptCompletely && mSelectedCryptPlug ) {
01779
01780
if( mSelectedCryptPlug->warnSendUnencrypted() ) {
01781
int ret =
01782 KMessageBox::warningYesNoCancel(
this,
01783 QString(
"<qt><b>"
01784 + i18n(
"Warning:")
01785 +
"</b><br>"
01786 + ((doEncrypt && !doEncryptCompletely)
01787 ? i18n(
"You specified not to encrypt some parts of this message, but"
01788
" you wanted to be warned not to send unencrypted messages!")
01789 : i18n(
"You specified not to encrypt this message, but"
01790
" you wanted to be warned not to send unencrypted messages!") )
01791 +
"<br> <br><b>"
01792 + i18n(
"Encrypt all parts of this message?")
01793 +
"</b></qt>" ),
01794 i18n(
"Encryption Warning"),
01795 KGuiItem( i18n(
"&Encrypt All Parts") ),
01796 KGuiItem( i18n(
"Send &as is") ) );
01797
if( ret == KMessageBox::Cancel )
01798 bOk =
false;
01799
else if( ret == KMessageBox::Yes ) {
01800 doEncrypt =
true;
01801 doEncryptCompletely =
true;
01802 }
01803 }
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814 }
01815 }
01816 }
01817
01818
if( bOk ) {
01819
01820
if( mSelectedCryptPlug && ( !mAtmList.isEmpty() ) &&
01821 ( doSignCompletely || doEncryptCompletely ) ) {
01822
for( KMAtmListViewItem* lvi = (KMAtmListViewItem*)mAtmItemList.first();
01823 lvi;
01824 lvi = (KMAtmListViewItem*)mAtmItemList.next() ) {
01825
if( doSignCompletely )
01826 lvi->setSign(
true );
01827
if( doEncryptCompletely )
01828 lvi->setEncrypt(
true );
01829 }
01830 }
01831 }
01832
01833
01834 QCString signCertFingerprint;
01835
01836
01837 KMMessage* extraMessage =
new KMMessage( *mMsg );
01838
01839
if( bOk )
01840 bOk = (composeMessage( pgpUserId,
01841 *mMsg, doSign, doEncrypt,
false,
01842 signCertFingerprint ) == Kpgp::Ok);
01843
if( bOk ) {
01844
bool saveMessagesEncrypted = mSelectedCryptPlug ? mSelectedCryptPlug->saveMessagesEncrypted()
01845 : true;
01846
01847 kdDebug(5006) <<
"\n\n" << endl;
01848 kdDebug(5006) <<
"KMComposeWin::applyChanges(void) - Send encrypted=" << doEncrypt <<
" Store encrypted=" << saveMessagesEncrypted << endl;
01849
01850
01851
#ifdef STRICT_RULES_OF_GERMAN_GOVERNMENT_01
01852
01853
01854
01855
01856
01857
01858
01859
01860
if( mSelectedCryptPlug
01861 && ( 0 <= mSelectedCryptPlug->libName().find(
"smime", 0,
false ) )
01862 && ( doEncrypt && saveMessagesEncrypted ) ){
01863
01864
if( doEncrypt && saveMessagesEncrypted ) {
01865 QString headTxt =
01866 i18n(
"Warning: Your S/MIME Plug-in configuration is unsafe.");
01867 QString encrTxt =
01868 i18n(
"Encrypted messages should be stored in unencrypted form; saving locally in encrypted form is not allowed.");
01869 QString footTxt =
01870 i18n(
"Please correct the wrong settings in KMail's Plug-in configuration pages as soon as possible.");
01871 QString question =
01872 i18n(
"Store message in the recommended way?");
01873
01874
if( KMessageBox::Yes == KMessageBox::warningYesNo(
this,
01875
"<qt><p><b>" + headTxt +
"</b><br>" + encrTxt +
"</p><p>"
01876 + footTxt +
"</p><p><b>" + question +
"</b></p></qt>",
01877 i18n(
"Unsafe S/MIME Configuration"),
01878 KGuiItem( i18n(
"Save &Unencrypted") ),
01879 KGuiItem( i18n(
"Save &Encrypted") ) ) ) {
01880 saveMessagesEncrypted =
false;
01881 }
01882 }
01883 }
01884 kdDebug(5006) <<
"KMComposeWin::applyChanges(void) - Send encrypted=" << doEncrypt <<
" Store encrypted=" << saveMessagesEncrypted << endl;
01885
#endif
01886
if( doEncrypt && ! saveMessagesEncrypted ){
01887
if( mSelectedCryptPlug ){
01888
for( KMAtmListViewItem* entry = (KMAtmListViewItem*)mAtmItemList.first();
01889 entry;
01890 entry = (KMAtmListViewItem*)mAtmItemList.next() )
01891 entry->setEncrypt(
false );
01892 }
01893 bOk = (composeMessage( pgpUserId,
01894 *extraMessage,
01895 doSign,
01896
false,
01897
true,
01898 signCertFingerprint ) == Kpgp::Ok);
01899 kdDebug(5006) <<
"KMComposeWin::applyChanges(void) - Store message in decrypted form." << endl;
01900 extraMessage->cleanupHeader();
01901 mMsg->setUnencryptedMsg( extraMessage );
01902 }
01903 }
01904
return bOk;
01905 }
01906
01907
01908 Kpgp::Result KMComposeWin::composeMessage( QCString pgpUserId,
01909 KMMessage& theMessage,
01910
bool doSign,
01911
bool doEncrypt,
01912
bool ignoreBcc,
01913 QCString& signCertFingerprint )
01914 {
01915 Kpgp::Result result = Kpgp::Ok;
01916
01917
01918 theMessage.setBody(
"This message is in MIME format." );
01919
01920
01921 QCString body = breakLinesAndApplyCodec();
01922
01923
if (body.isNull())
return Kpgp::Failure;
01924
01925
if (body.isEmpty()) body =
"\n";
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
if( body[body.length()-1] !=
'\n' ) {
01939 kdDebug(5006) <<
"Added an <LF> on the last line" << endl;
01940 body +=
"\n";
01941 }
01942
01943
01944 theMessage.deleteBodyParts();
01945 theMessage.removeHeaderField(
"Content-Type");
01946 theMessage.removeHeaderField(
"Content-Transfer-Encoding");
01947 theMessage.setAutomaticFields(TRUE);
01948
01949
01950 KMMessagePart newBodyPart;
01951
01952
01953
int previousBoundaryLevel = 0;
01954
01955
01956
01957
01958
bool earlyAddAttachments =
01959 mSelectedCryptPlug && ( !mAtmList.isEmpty() ) && (doSign || doEncrypt);
01960
01961
bool allAttachmentsAreInBody = earlyAddAttachments ?
true :
false;
01962
01963
01964
if( earlyAddAttachments ) {
01965
bool someOk =
false;
01966
int idx;
01967 KMMessagePart *attachPart;
01968
for( idx=0, attachPart = mAtmList.first();
01969 attachPart;
01970 attachPart=mAtmList.next(),
01971 ++idx )
01972
if( doEncrypt == encryptFlagOfAttachment( idx )
01973 && doSign == signFlagOfAttachment( idx ) )
01974 someOk =
true;
01975
else
01976 allAttachmentsAreInBody =
false;
01977
if( !allAttachmentsAreInBody && !someOk )
01978 earlyAddAttachments =
false;
01979 }
01980
01981 KMMessagePart oldBodyPart;
01982 oldBodyPart.setTypeStr( earlyAddAttachments ?
"multipart" :
"text" );
01983 oldBodyPart.setSubtypeStr(earlyAddAttachments ?
"mixed" :
"plain");
01984 oldBodyPart.setContentDisposition(
"inline" );
01985
01986 QCString boundaryCStr;
01987
01988
bool isQP = kmkernel->msgSender()->sendQuotedPrintable();
01989
01990
if( earlyAddAttachments ) {
01991
01992 ++previousBoundaryLevel;
01993 DwMediaType tmpCT;
01994 tmpCT.CreateBoundary( previousBoundaryLevel );
01995 boundaryCStr = tmpCT.Boundary().c_str();
01996
01997 KMMessagePart innerBodyPart;
01998 innerBodyPart.setTypeStr(
"text" );
01999 innerBodyPart.setSubtypeStr(
"plain");
02000 innerBodyPart.setContentDisposition(
"inline" );
02001 QValueList<int> allowedCTEs;
02002
02003 innerBodyPart.setBodyAndGuessCte(body, allowedCTEs, !isQP && !doSign,
02004 doSign);
02005 innerBodyPart.setCharset(mCharset);
02006 innerBodyPart.setBodyEncoded( body );
02007 DwBodyPart* innerDwPart = theMessage.createDWBodyPart( &innerBodyPart );
02008 innerDwPart->Assemble();
02009 body =
"--";
02010 body += boundaryCStr;
02011 body +=
"\n";
02012 body += innerDwPart->AsString().c_str();
02013
delete innerDwPart;
02014 innerDwPart = 0;
02015
02016
02017
int idx;
02018 KMMessagePart *attachPart;
02019
for( idx=0, attachPart = mAtmList.first();
02020 attachPart;
02021 attachPart=mAtmList.next(),
02022 ++idx ) {
02023
bool bEncrypt = encryptFlagOfAttachment( idx );
02024
bool bSign = signFlagOfAttachment( idx );
02025
if( !mSelectedCryptPlug
02026 || ( ( doEncrypt == bEncrypt ) && ( doSign == bSign ) ) ) {
02027
02028
02029
02030
if( bSign || bEncrypt ) {
02031 QCString cte = attachPart->cteStr().lower();
02032
if( (
"8bit" == cte )
02033 || ( ( attachPart->type() == DwMime::kTypeText )
02034 && (
"7bit" == cte ) ) ) {
02035 QByteArray body = attachPart->bodyDecodedBinary();
02036 QValueList<int> dummy;
02037 attachPart->setBodyAndGuessCte(body, dummy,
false, bSign);
02038 kdDebug(5006) <<
"Changed encoding of message part from "
02039 << cte <<
" to " << attachPart->cteStr() << endl;
02040 }
02041 }
02042 innerDwPart = theMessage.createDWBodyPart( attachPart );
02043 innerDwPart->Assemble();
02044 body +=
"\n--";
02045 body += boundaryCStr;
02046 body +=
"\n";
02047 body += innerDwPart->AsString().c_str();
02048
delete innerDwPart;
02049 innerDwPart = 0;
02050 }
02051 }
02052 body +=
"\n--";
02053 body += boundaryCStr;
02054 body +=
"--\n";
02055 }
02056
else
02057 {
02058 QValueList<int> allowedCTEs;
02059
02060 oldBodyPart.setBodyAndGuessCte(body, allowedCTEs, !isQP && !doSign,
02061 doSign);
02062 oldBodyPart.setCharset(mCharset);
02063 }
02064
02065 oldBodyPart.setBodyEncoded( body );
02066
02067 QCString encodedBody;
02068
02069
if( doSign || doEncrypt ) {
02070
if( mSelectedCryptPlug ) {
02071
02072 DwBodyPart* dwPart = theMessage.createDWBodyPart( &oldBodyPart );
02073 dwPart->Assemble();
02074 encodedBody = dwPart->AsString().c_str();
02075
delete dwPart;
02076 dwPart = 0;
02077
02078
02079
if( !boundaryCStr.isEmpty() ) {
02080
int boundPos = encodedBody.find(
'\n' );
02081
if( -1 < boundPos ) {
02082
02083 QCString bStr(
";\n boundary=\"" );
02084 bStr += boundaryCStr;
02085 bStr +=
"\"";
02086 encodedBody.insert( boundPos, bStr );
02087 }
02088 }
02089
02090
02091
02092
if( (0 <= mSelectedCryptPlug->libName().find(
"smime", 0,
false )) ||
02093 (0 <= mSelectedCryptPlug->libName().find(
"openpgp", 0,
false )) ) {
02094
02095
02096 kdDebug(5006) <<
"Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)" << endl;
02097 encodedBody = KMMessage::lf2crlf( encodedBody );
02098 kdDebug(5006) <<
" done." << endl;
02099
02100 }
02101 }
else {
02102 encodedBody = body;
02103 }
02104 }
02105
02106
if( doSign ) {
02107
if( mSelectedCryptPlug ) {
02108 StructuringInfoWrapper structuring( mSelectedCryptPlug );
02109
02110
02111
02112 QByteArray signature = pgpSignedMsg( encodedBody,
02113 structuring,
02114 signCertFingerprint );
02115 kdDebug(5006) <<
" size of signature: " << signature.count() <<
"\n" << endl;
02116 result = signature.isEmpty() ? Kpgp::Failure : Kpgp::Ok;
02117
if( result == Kpgp::Ok ) {
02118 result = processStructuringInfo( QString::fromUtf8( mSelectedCryptPlug->bugURL() ),
02119 previousBoundaryLevel + doEncrypt ? 3 : 2,
02120 oldBodyPart.contentDescription(),
02121 oldBodyPart.typeStr(),
02122 oldBodyPart.subtypeStr(),
02123 oldBodyPart.contentDisposition(),
02124 oldBodyPart.contentTransferEncodingStr(),
02125 encodedBody,
02126
"signature",
02127 signature,
02128 structuring,
02129 newBodyPart ) ? Kpgp::Ok : Kpgp::Failure;
02130
if( result == Kpgp::Ok ) {
02131
if( newBodyPart.name().isEmpty() )
02132 newBodyPart.setName(
"signed message part");
02133 newBodyPart.setCharset( mCharset );
02134 }
else
02135 KMessageBox::sorry(
this, mErrorProcessingStructuringInfo );
02136 }
02137 }
02138
else if ( !doEncrypt ) {
02139
02140 Kpgp::Block block;
02141 block.setText( encodedBody );
02142
02143
02144 result = block.clearsign( pgpUserId, mCharset );
02145
02146
if( result == Kpgp::Ok ) {
02147 newBodyPart.setType( oldBodyPart.type() );
02148 newBodyPart.setSubtype( oldBodyPart.subtype() );
02149 newBodyPart.setCharset( oldBodyPart.charset() );
02150 newBodyPart.setContentTransferEncodingStr( oldBodyPart.contentTransferEncodingStr() );
02151 newBodyPart.setContentDescription( oldBodyPart.contentDescription() );
02152 newBodyPart.setContentDisposition( oldBodyPart.contentDisposition() );
02153 newBodyPart.setBodyEncoded( block.text() );
02154 }
02155
else if ( result == Kpgp::Failure )
02156 KMessageBox::sorry(
this,
02157 i18n(
"<qt><p>This message could not be signed.</p>%1</qt>")
02158 .arg( mErrorNoCryptPlugAndNoBuildIn ));
02159 }
02160 }
02161
02162
if( result == Kpgp::Ok ) {
02163
02164 QString _to = to().simplifyWhiteSpace();
02165
if( !cc().isEmpty() ) {
02166
if( !_to.endsWith(
",") )
02167 _to +=
",";
02168 _to += cc().simplifyWhiteSpace();
02169 }
02170 QStringList recipientsWithoutBcc = KMMessage::splitEmailAddrList(_to);
02171
02172
02173
if( doEncrypt && !ignoreBcc && !theMessage.bcc().isEmpty() ) {
02174 QStringList bccRecips = KMMessage::splitEmailAddrList( theMessage.bcc() );
02175
for( QStringList::ConstIterator it = bccRecips.begin();
02176 it != bccRecips.end();
02177 ++it ) {
02178 QStringList tmpRecips( recipientsWithoutBcc );
02179 tmpRecips << *it;
02180
02181 KMMessage* yetAnotherMessageForBCC =
new KMMessage( theMessage );
02182 KMMessagePart tmpNewBodyPart = newBodyPart;
02183 result = encryptMessage( yetAnotherMessageForBCC,
02184 tmpRecips,
02185 doSign, doEncrypt, encodedBody,
02186 previousBoundaryLevel,
02187 oldBodyPart,
02188 earlyAddAttachments, allAttachmentsAreInBody,
02189 tmpNewBodyPart,
02190 signCertFingerprint );
02191
if( result == Kpgp::Ok ){
02192 yetAnotherMessageForBCC->setHeaderField(
"X-KMail-Recipients", *it );
02193 mBccMsgList.append( yetAnotherMessageForBCC );
02194
02195 }
02196 }
02197 theMessage.setHeaderField(
"X-KMail-Recipients", recipientsWithoutBcc.join(
",") );
02198 }
02199
02200
02201
if( result == Kpgp::Ok ){
02202 result = encryptMessage( &theMessage,
02203 recipientsWithoutBcc,
02204 doSign, doEncrypt, encodedBody,
02205 previousBoundaryLevel,
02206 oldBodyPart,
02207 earlyAddAttachments, allAttachmentsAreInBody,
02208 newBodyPart,
02209 signCertFingerprint );
02210 }
02211
02212 }
02213
return result;
02214 }
02215
02216
02217
bool KMComposeWin::queryExit ()
02218 {
02219
return true;
02220 }
02221
02222 Kpgp::Result KMComposeWin::getEncryptionCertificates(
02223
const QStringList& recipients,
02224 QCString& encryptionCertificates )
02225 {
02226 Kpgp::Result result = Kpgp::Ok;
02227
02228
02229
if ( -1 != mSelectedCryptPlug->libName().find(
"openpgp" ) ) {
02230
02231
02232
02233
const KMIdentity & ident =
02234 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
02235
const QCString userKeyId = ident.
pgpIdentity();
02236 Kpgp::Module *pgp = Kpgp::Module::getKpgp();
02237 Kpgp::KeyIDList encryptionKeyIds;
02238
02239
02240
02241
02242
const bool bEncryptToSelf_Old = pgp->encryptToSelf();
02243 pgp->setEncryptToSelf( mSelectedCryptPlug->alwaysEncryptToSelf() );
02244 result = pgp->getEncryptionKeys( encryptionKeyIds, recipients, userKeyId );
02245
02246 pgp->setEncryptToSelf( bEncryptToSelf_Old );
02247
02248
if ( result == Kpgp::Ok && !encryptionKeyIds.isEmpty() ) {
02249
02250
for ( Kpgp::KeyIDList::ConstIterator it = encryptionKeyIds.begin();
02251 it != encryptionKeyIds.end(); ++it ) {
02252
const Kpgp::Key* key = pgp->publicKey( *it );
02253
if ( key ) {
02254 QCString certFingerprint = key->primaryFingerprint();
02255 kdDebug(5006) <<
"Fingerprint of encryption key: "
02256 << certFingerprint << endl;
02257
02258
if( !encryptionCertificates.isEmpty() )
02259 encryptionCertificates +=
'\1';
02260 encryptionCertificates += certFingerprint;
02261 }
02262 }
02263 }
02264 }
02265
else {
02266
02267 QStringList allRecipients = recipients;
02268
if ( mSelectedCryptPlug->alwaysEncryptToSelf() )
02269 allRecipients << from();
02270
for ( QStringList::ConstIterator it = allRecipients.begin();
02271 it != allRecipients.end();
02272 ++it ) {
02273 QCString certFingerprint = getEncryptionCertificate( *it );
02274
02275
if ( certFingerprint.isEmpty() ) {
02276
02277 encryptionCertificates.truncate( 0 );
02278
return Kpgp::Canceled;
02279 }
02280
02281 certFingerprint.remove( 0, certFingerprint.findRev(
'(' ) + 1 );
02282 certFingerprint.truncate( certFingerprint.length() - 1 );
02283 kdDebug(5006) <<
"\n\n Recipient: " << *it
02284 <<
"\nFingerprint of encryption key: "
02285 << certFingerprint <<
"\n\n" << endl;
02286
02287
const bool certOkay =
02288 checkForEncryptCertificateExpiry( *it, certFingerprint );
02289
if( certOkay ) {
02290
if( !encryptionCertificates.isEmpty() )
02291 encryptionCertificates +=
'\1';
02292 encryptionCertificates += certFingerprint;
02293 }
02294
else {
02295
02296
02297 encryptionCertificates.truncate( 0 );
02298
return Kpgp::Failure;
02299 }
02300 }
02301 }
02302
return result;
02303 }
02304
02305 Kpgp::Result KMComposeWin::encryptMessage( KMMessage* msg,
02306
const QStringList& recipients,
02307
bool doSign,
02308
bool doEncrypt,
02309
const QCString& encodedBody,
02310
int previousBoundaryLevel,
02311
const KMMessagePart& oldBodyPart,
02312
bool earlyAddAttachments,
02313
bool allAttachmentsAreInBody,
02314 KMMessagePart newBodyPart,
02315 QCString& signCertFingerprint )
02316 {
02317 Kpgp::Result result = Kpgp::Ok;
02318
if(!msg)
02319 {
02320 kdDebug(5006) <<
"KMComposeWin::encryptMessage() : msg == 0!\n" << endl;
02321
return Kpgp::Failure;
02322 }
02323
02324
02325
02326 QCString encryptCertFingerprints;
02327
02328
02329
if ( mSelectedCryptPlug ) {
02330
bool encrypt = doEncrypt;
02331
if( !encrypt ) {
02332
02333
for ( KMAtmListViewItem* atmlvi =
02334 static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
02335 atmlvi;
02336 atmlvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
02337
if ( atmlvi->isEncrypt() ) {
02338 encrypt =
true;
02339
break;
02340 }
02341 }
02342 }
02343
if ( encrypt ) {
02344 result = getEncryptionCertificates( recipients,
02345 encryptCertFingerprints );
02346
if ( result != Kpgp::Ok )
02347
return result;
02348
if ( encryptCertFingerprints.isEmpty() ) {
02349
02350 setEncryption(
false,
false );
02351 doEncrypt =
false;
02352 }
02353 }
02354 }
02355
02356
02357
if( doEncrypt ) {
02358 QCString innerContent;
02359
if( doSign && mSelectedCryptPlug ) {
02360 DwBodyPart* dwPart = msg->createDWBodyPart( &newBodyPart );
02361 dwPart->Assemble();
02362 innerContent = dwPart->AsString().c_str();
02363
delete dwPart;
02364 dwPart = 0;
02365 }
else
02366 innerContent = encodedBody;
02367
02368
02369 {
02370
if( mSelectedCryptPlug ) {
02371
if( (0 <= mSelectedCryptPlug->libName().find(
"smime", 0,
false )) ||
02372 (0 <= mSelectedCryptPlug->libName().find(
"openpgp", 0,
false )) ) {
02373
02374
02375 kdDebug(5006) <<
"Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)" << endl;
02376 innerContent = KMMessage::lf2crlf( innerContent );
02377 kdDebug(5006) <<
" done." << endl;
02378 }
02379
02380 StructuringInfoWrapper structuring( mSelectedCryptPlug );
02381
02382 QByteArray encryptedBody;
02383 result = pgpEncryptedMsg( encryptedBody, innerContent,
02384 structuring,
02385 encryptCertFingerprints );
02386
02387
if( Kpgp::Ok == result ) {
02388 result = processStructuringInfo( QString::fromUtf8( mSelectedCryptPlug->bugURL() ),
02389 previousBoundaryLevel + doEncrypt ? 2 : 1,
02390 newBodyPart.contentDescription(),
02391 newBodyPart.typeStr(),
02392 newBodyPart.subtypeStr(),
02393 newBodyPart.contentDisposition(),
02394 newBodyPart.contentTransferEncodingStr(),
02395 innerContent,
02396
"encrypted data",
02397 encryptedBody,
02398 structuring,
02399 newBodyPart ) ? Kpgp::Ok : Kpgp::Failure;
02400
if( Kpgp::Ok == result ) {
02401
if( newBodyPart.name().isEmpty() )
02402 newBodyPart.setName(
"encrypted message part");
02403 }
else if ( Kpgp::Failure == result )
02404 KMessageBox::sorry(
this, mErrorProcessingStructuringInfo);
02405 }
else if ( Kpgp::Failure == result )
02406 KMessageBox::sorry(
this,
02407 i18n(
"<qt><p><b>This message could not be encrypted!</b></p>"
02408
"<p>The Crypto Plug-in '%1' did not return an encoded text "
02409
"block.</p>"
02410
"<p>Probably a recipient's public key was not found or is "
02411
"untrusted.</p></qt>")
02412 .arg(mSelectedCryptPlug->libName()));
02413 }
else {
02414
02415 Kpgp::Block block;
02416 block.setText( innerContent );
02417
02418
02419
const KMIdentity & ident =
02420 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
02421 QCString pgpUserId = ident.
pgpIdentity();
02422
02423
02424 result = block.encrypt( recipients, pgpUserId, doSign, mCharset );
02425
02426
if( Kpgp::Ok == result ) {
02427 newBodyPart.setBodyEncodedBinary( block.text() );
02428 newBodyPart.setCharset( oldBodyPart.charset() );
02429 }
02430
else if( Kpgp::Failure == result ) {
02431 KMessageBox::sorry(
this,
02432 i18n(
"<qt><p>This message could not be encrypted!</p>%1</qt>")
02433 .arg( mErrorNoCryptPlugAndNoBuildIn ));
02434 }
02435 }
02436 }
02437 }
02438
02439
02440
if( Kpgp::Ok == result ) {
02441
const KMMessagePart& ourFineBodyPart( (doSign || doEncrypt)
02442 ? newBodyPart
02443 : oldBodyPart );
02444
if( !mAtmList.isEmpty()
02445 && ( !earlyAddAttachments || !allAttachmentsAreInBody ) ) {
02446
02447 msg->headers().ContentType().FromString(
"Multipart/Mixed" );
02448 kdDebug(5006) <<
"KMComposeWin::encryptMessage() : set top level Content-Type to Multipart/Mixed" << endl;
02449
02450
02451
02452
02453 msg->addBodyPart( &ourFineBodyPart );
02454
02455
02456
02457
int idx;
02458 KMMessagePart newAttachPart;
02459 KMMessagePart *attachPart;
02460
for( idx=0, attachPart = mAtmList.first();
02461 attachPart;
02462 attachPart = mAtmList.next(), ++idx ) {
02463 kdDebug(5006) <<
" processing " << idx <<
". attachment" << endl;
02464
02465
const bool cryptFlagsDifferent = mSelectedCryptPlug
02466 ? ( (encryptFlagOfAttachment( idx ) != doEncrypt)
02467 || (signFlagOfAttachment( idx ) != doSign) )
02468 :
false;
02469
const bool encryptThisNow = !mNeverEncrypt && ( cryptFlagsDifferent ? encryptFlagOfAttachment( idx ) : false );
02470
const bool signThisNow = !mNeverSign && ( cryptFlagsDifferent ? signFlagOfAttachment( idx ) : false );
02471
02472
if( cryptFlagsDifferent || !earlyAddAttachments ) {
02473
02474
if( encryptThisNow || signThisNow ) {
02475
02476 KMMessagePart& rEncryptMessagePart( *attachPart );
02477
02478
02479
02480 QCString cte = attachPart->cteStr().lower();
02481
if( (
"8bit" == cte )
02482 || ( ( attachPart->type() == DwMime::kTypeText )
02483 && (
"7bit" == cte ) ) ) {
02484 QByteArray body = attachPart->bodyDecodedBinary();
02485 QValueList<int> dummy;
02486 attachPart->setBodyAndGuessCte(body, dummy,
false,
true);
02487 kdDebug(5006) <<
"Changed encoding of message part from "
02488 << cte <<
" to " << attachPart->cteStr() << endl;
02489 }
02490 DwBodyPart* innerDwPart = msg->createDWBodyPart( attachPart );
02491 innerDwPart->Assemble();
02492 QCString encodedAttachment = innerDwPart->AsString().c_str();
02493
delete innerDwPart;
02494 innerDwPart = 0;
02495
02496
if( (0 <= mSelectedCryptPlug->libName().find(
"smime", 0,
false )) ||
02497 (0 <= mSelectedCryptPlug->libName().find(
"openpgp", 0,
false )) ) {
02498
02499
02500 kdDebug(5006) <<
"Converting LF to CRLF (see RfC 2633, 3.1.1 Canonicalization)" << endl;
02501 encodedAttachment = KMMessage::lf2crlf( encodedAttachment );
02502 kdDebug(5006) <<
" done." << endl;
02503 }
02504
02505
02506
if( signThisNow ) {
02507 kdDebug(5006) <<
" sign " << idx <<
". attachment separately" << endl;
02508 StructuringInfoWrapper structuring( mSelectedCryptPlug );
02509
02510 QByteArray signature = pgpSignedMsg( encodedAttachment,
02511 structuring,
02512 signCertFingerprint );
02513 result = signature.isEmpty() ? Kpgp::Failure : Kpgp::Ok;
02514
if( Kpgp::Ok == result ) {
02515 result = processStructuringInfo( QString::fromUtf8( mSelectedCryptPlug->bugURL() ),
02516 previousBoundaryLevel + 10 + idx,
02517 attachPart->contentDescription(),
02518 attachPart->typeStr(),
02519 attachPart->subtypeStr(),
02520 attachPart->contentDisposition(),
02521 attachPart->contentTransferEncodingStr(),
02522 encodedAttachment,
02523
"signature",
02524 signature,
02525 structuring,
02526 newAttachPart ) ? Kpgp::Ok : Kpgp::Failure;
02527
if( Kpgp::Ok == result ) {
02528
if( newAttachPart.name().isEmpty() )
02529 newAttachPart.setName(
"signed attachment");
02530
if( encryptThisNow ) {
02531 rEncryptMessagePart = newAttachPart;
02532 DwBodyPart* dwPart = msg->createDWBodyPart( &newAttachPart );
02533 dwPart->Assemble();
02534 encodedAttachment = dwPart->AsString().c_str();
02535
delete dwPart;
02536 dwPart = 0;
02537 }
02538 }
else
02539 KMessageBox::sorry(
this, mErrorProcessingStructuringInfo );
02540 }
else {
02541
02542
break;
02543 }
02544 }
02545
if( encryptThisNow ) {
02546 kdDebug(5006) <<
" encrypt " << idx <<
". attachment separately" << endl;
02547 StructuringInfoWrapper structuring( mSelectedCryptPlug );
02548 QByteArray encryptedBody;
02549 result = pgpEncryptedMsg( encryptedBody, encodedAttachment,
02550 structuring,
02551 encryptCertFingerprints );
02552
02553
if( Kpgp::Ok == result ) {
02554 result = processStructuringInfo( QString::fromUtf8( mSelectedCryptPlug->bugURL() ),
02555 previousBoundaryLevel + 11 + idx,
02556 rEncryptMessagePart.contentDescription(),
02557 rEncryptMessagePart.typeStr(),
02558 rEncryptMessagePart.subtypeStr(),
02559 rEncryptMessagePart.contentDisposition(),
02560 rEncryptMessagePart.contentTransferEncodingStr(),
02561 encodedAttachment,
02562
"encrypted data",
02563 encryptedBody,
02564 structuring,
02565 newAttachPart ) ? Kpgp::Ok : Kpgp::Failure;
02566
if( Kpgp::Ok == result ) {
02567
if( newAttachPart.name().isEmpty() ) {
02568 newAttachPart.setName(
"encrypted attachment");
02569 }
02570 }
else if ( Kpgp::Failure == result )
02571 KMessageBox::sorry(
this, mErrorProcessingStructuringInfo);
02572 }
02573 }
02574 msg->addBodyPart( &newAttachPart );
02575 }
else
02576 msg->addBodyPart( attachPart );
02577
02578 kdDebug(5006) <<
" added " << idx <<
". attachment to this Multipart/Mixed" << endl;
02579 }
else {
02580 kdDebug(5006) <<
" " << idx <<
". attachment was part of the BODY already" << endl;
02581 }
02582 }
02583 }
else {
02584
if( ourFineBodyPart.originalContentTypeStr() ) {
02585
02586
02587 msg->headers().ContentType().FromString( ourFineBodyPart.originalContentTypeStr() );
02588
02589
02590 msg->headers().ContentType().Parse();
02591
02592
02593 kdDebug(5006) <<
"KMComposeWin::encryptMessage() : set top level Content-Type from originalContentTypeStr()" << endl;
02594 }
else {
02595 msg->headers().ContentType().FromString( ourFineBodyPart.typeStr() +
"/" + ourFineBodyPart.subtypeStr() );
02596 kdDebug(5006) <<
"KMComposeWin::encryptMessage() : set top level Content-Type from typeStr()/subtypeStr()" << endl;
02597 }
02598
02599
02600
if ( !ourFineBodyPart.charset().isEmpty() )
02601 msg->setCharset( ourFineBodyPart.charset() );
02602
02603
02604 msg->setHeaderField(
"Content-Transfer-Encoding",
02605 ourFineBodyPart.contentTransferEncodingStr() );
02606
02607
02608 msg->setHeaderField(
"Content-Description",
02609 ourFineBodyPart.contentDescription() );
02610 msg->setHeaderField(
"Content-Disposition",
02611 ourFineBodyPart.contentDisposition() );
02612
02613 kdDebug(5006) <<
"KMComposeWin::encryptMessage() : top level headers and body adjusted" << endl;
02614
02615
02616
02617 msg->setMultiPartBody( ourFineBodyPart.body() );
02618
02619
02620
02621 }
02622
02623 }
02624
return result;
02625 }
02626
02627
02628
bool KMComposeWin::processStructuringInfo(
const QString bugURL,
02629 uint boundaryLevel,
02630
const QString contentDescClear,
02631
const QCString contentTypeClear,
02632
const QCString contentSubtypeClear,
02633
const QCString contentDispClear,
02634
const QCString contentTEncClear,
02635
const QCString& clearCStr,
02636
const QString contentDescCiph,
02637
const QByteArray& ciphertext,
02638
const StructuringInfoWrapper& structuring,
02639 KMMessagePart& resultingPart )
02640 {
02641
#ifdef DEBUG
02642
kdDebug(5006) <<
"||| entering KMComposeWin::processStructuringInfo()" << endl;
02643
#endif
02644
02645
if(!mMsg)
02646 {
02647 kdDebug(5006) <<
"KMComposeWin::processStructuringInfo() : mMsg == 0!\n" << endl;
02648
return FALSE;
02649 }
02650
02651
bool bOk =
true;
02652
02653
if( structuring.data.makeMimeObject ) {
02654
02655 QCString mainHeader;
02656
02657
if( structuring.data.contentTypeMain
02658 && 0 < strlen( structuring.data.contentTypeMain ) ) {
02659 mainHeader =
"Content-Type: ";
02660 mainHeader += structuring.data.contentTypeMain;
02661 }
else {
02662 mainHeader =
"Content-Type: ";
02663
if( structuring.data.makeMultiMime )
02664 mainHeader +=
"text/plain";
02665
else {
02666 mainHeader += contentTypeClear;
02667 mainHeader +=
'/';
02668 mainHeader += contentSubtypeClear;
02669 }
02670 }
02671
02672 QCString boundaryCStr;
02673
02674
02675
if( structuring.data.makeMultiMime ) {
02676
02677
02678 DwMediaType tmpCT;
02679 tmpCT.CreateBoundary( boundaryLevel );
02680 boundaryCStr = tmpCT.Boundary().c_str();
02681
02682
int boundA = mainHeader.find(
"boundary=", 0,
false);
02683
int boundZ;
02684
if( -1 < boundA ) {
02685
02686
while( 0 < boundA
02687 &&
' ' == mainHeader[ boundA-1 ] )
02688 --boundA;
02689
if( 0 < boundA
02690 &&
';' == mainHeader[ boundA-1 ] )
02691 --boundA;
02692 boundZ = mainHeader.find(
';', boundA+1);
02693
if( -1 == boundZ )
02694 mainHeader.truncate( boundA );
02695
else
02696 mainHeader.remove( boundA, (1 + boundZ - boundA) );
02697 }
02698
02699 QCString bStr(
";boundary=\"" );
02700 bStr += boundaryCStr;
02701 bStr +=
"\"";
02702 mainHeader += bStr;
02703 }
02704
02705
if( structuring.data.contentTypeMain
02706 && 0 < strlen( structuring.data.contentTypeMain ) ) {
02707
02708
if( structuring.data.contentDispMain
02709 && 0 < strlen( structuring.data.contentDispMain ) ) {
02710 mainHeader +=
"\nContent-Disposition: ";
02711 mainHeader += structuring.data.contentDispMain;
02712 }
02713
if( structuring.data.contentTEncMain
02714 && 0 < strlen( structuring.data.contentTEncMain ) ) {
02715
02716 mainHeader +=
"\nContent-Transfer-Encoding: ";
02717 mainHeader += structuring.data.contentTEncMain;
02718 }
02719
02720 }
else {
02721
if( 0 < contentDescClear.length() ) {
02722 mainHeader +=
"\nContent-Description: ";
02723 mainHeader += contentDescClear.utf8();
02724 }
02725
if( 0 < contentDispClear.length() ) {
02726 mainHeader +=
"\nContent-Disposition: ";
02727 mainHeader += contentDispClear;
02728 }
02729
if( 0 < contentTEncClear.length() ) {
02730 mainHeader +=
"\nContent-Transfer-Encoding: ";
02731 mainHeader += contentTEncClear;
02732 }
02733 }
02734
02735
02736 DwString mainDwStr;
02737 mainDwStr = mainHeader;
02738 DwBodyPart mainDwPa( mainDwStr, 0 );
02739 mainDwPa.Parse();
02740 KMMessage::bodyPart(&mainDwPa, &resultingPart);
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
if( ! structuring.data.makeMultiMime ) {
02755
02756
if( structuring.data.includeCleartext ) {
02757 QCString bodyText( clearCStr );
02758 bodyText +=
'\n';
02759 bodyText += ciphertext;
02760 resultingPart.setBodyEncoded( bodyText );
02761 }
else
02762 resultingPart.setBodyEncodedBinary( ciphertext );
02763
02764 }
else {
02765
02766 QCString versCStr, codeCStr;
02767
02768
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782
02783
02784
02785
02786
02787
02788
02789
02790
02791
02792
02793
02794
02795
02796
02797
if( structuring.data.contentTypeVersion
02798 && 0 < strlen( structuring.data.contentTypeVersion ) ) {
02799
02800 DwString versStr(
"Content-Type: " );
02801 versStr += structuring.data.contentTypeVersion;
02802
02803 versStr +=
"\nContent-Description: ";
02804 versStr +=
"version code";
02805
02806
if( structuring.data.contentDispVersion
02807 && 0 < strlen( structuring.data.contentDispVersion ) ) {
02808 versStr +=
"\nContent-Disposition: ";
02809 versStr += structuring.data.contentDispVersion;
02810 }
02811
if( structuring.data.contentTEncVersion
02812 && 0 < strlen( structuring.data.contentTEncVersion ) ) {
02813 versStr +=
"\nContent-Transfer-Encoding: ";
02814 versStr += structuring.data.contentTEncVersion;
02815 }
02816
02817 DwBodyPart versDwPa( versStr, 0 );
02818 versDwPa.Parse();
02819 KMMessagePart versKmPa;
02820 KMMessage::bodyPart(&versDwPa, &versKmPa);
02821 versKmPa.setBodyEncoded( structuring.data.bodyTextVersion );
02822
02823 versCStr = versDwPa.Headers().AsString().c_str();
02824
02825 versCStr +=
"\n\n";
02826 versCStr += versKmPa.body();
02827 }
02828
02829
02830
02831
if( structuring.data.contentTypeCode
02832 && 0 < strlen( structuring.data.contentTypeCode ) ) {
02833
02834 DwString codeStr(
"Content-Type: " );
02835 codeStr += structuring.data.contentTypeCode;
02836
if( structuring.data.contentTEncCode
02837 && 0 < strlen( structuring.data.contentTEncCode ) ) {
02838 codeStr +=
"\nContent-Transfer-Encoding: ";
02839 codeStr += structuring.data.contentTEncCode;
02840
02841
02842
02843 }
02844
if( !contentDescCiph.isEmpty() ) {
02845 codeStr +=
"\nContent-Description: ";
02846 codeStr += contentDescCiph.utf8();
02847 }
02848
if( structuring.data.contentDispCode
02849 && 0 < strlen( structuring.data.contentDispCode ) ) {
02850 codeStr +=
"\nContent-Disposition: ";
02851 codeStr += structuring.data.contentDispCode;
02852 }
02853
02854 DwBodyPart codeDwPa( codeStr, 0 );
02855 codeDwPa.Parse();
02856 KMMessagePart codeKmPa;
02857 KMMessage::bodyPart(&codeDwPa, &codeKmPa);
02858
02859
02860
02861
02862
02863
02864 codeKmPa.setBodyEncodedBinary( ciphertext );
02865
02866 codeCStr = codeDwPa.Headers().AsString().c_str();
02867
02868 codeCStr +=
"\n\n";
02869 codeCStr += codeKmPa.body();
02870
#if 0
02871
kdDebug(5006) <<
"***************************************" << endl;
02872 kdDebug(5006) <<
"***************************************" << endl;
02873 kdDebug(5006) << codeCStr << endl;
02874 kdDebug(5006) <<
"***************************************" << endl;
02875 kdDebug(5006) <<
"***************************************" << endl;
02876
#endif
02877
}
else {
02878
02879
02880 KMessageBox::sorry(
this,
02881 i18n(
"<qt><p>Error: The Crypto Plug-in '%1' returned<br>"
02882
" \" structuring.makeMultiMime \"<br>"
02883
"but did <b>not</b> specify a Content-Type header "
02884
"for the ciphertext that was generated.</p>"
02885
"<p>Please report this bug:<br>%2</p></qt>")
02886 .arg(mSelectedCryptPlug->libName())
02887 .arg(bugURL) );
02888 bOk =
false;
02889 }
02890
02891 QCString mainStr;
02892
02893 mainStr =
"--";
02894 mainStr += boundaryCStr;
02895
02896
if( structuring.data.includeCleartext && (0 < clearCStr.length()) ) {
02897 mainStr +=
"\n";
02898 mainStr += clearCStr;
02899 mainStr +=
"\n--";
02900 mainStr += boundaryCStr;
02901 }
02902
if( 0 < versCStr.length() ) {
02903 mainStr +=
"\n";
02904 mainStr += versCStr;
02905 mainStr +=
"\n\n--";
02906 mainStr += boundaryCStr;
02907 }
02908
if( 0 < codeCStr.length() ) {
02909 mainStr +=
"\n";
02910 mainStr += codeCStr;
02911
02912 mainStr +=
"\n--";
02913 mainStr += boundaryCStr;
02914 }
02915 mainStr +=
"--\n";
02916
02917 resultingPart.setBodyEncoded( mainStr );
02918
02919 }
02920
02921
02922
02923
02924
02925
02926
02927 }
else {
02928
02929
02930
02931
02932
02933
02934 resultingPart.setContentDescription( contentDescClear );
02935 resultingPart.setTypeStr( contentTypeClear );
02936 resultingPart.setSubtypeStr( contentSubtypeClear );
02937 resultingPart.setContentDisposition( contentDispClear );
02938 resultingPart.setContentTransferEncodingStr( contentTEncClear );
02939 QCString resultingBody;
02940
02941
if( structuring.data.flatTextPrefix
02942 && strlen( structuring.data.flatTextPrefix ) )
02943 resultingBody += structuring.data.flatTextPrefix;
02944
if( structuring.data.includeCleartext ) {
02945
if( !clearCStr.isEmpty() )
02946 resultingBody += clearCStr;
02947
if( structuring.data.flatTextSeparator
02948 && strlen( structuring.data.flatTextSeparator ) )
02949 resultingBody += structuring.data.flatTextSeparator;
02950 }
02951
if( ciphertext
02952 && strlen( ciphertext ) )
02953 resultingBody += *ciphertext;
02954
else {
02955
02956 KMessageBox::sorry(
this,
02957 i18n(
"<qt><p>Error: The Crypto Plug-in '%1' did not return "
02958
"any encoded data.</p>"
02959
"<p>Please report this bug:<br>%2</p></qt>")
02960 .arg(mSelectedCryptPlug->libName())
02961 .arg(bugURL) );
02962 bOk =
false;
02963 }
02964
if( structuring.data.flatTextPostfix
02965 && strlen( structuring.data.flatTextPostfix ) )
02966 resultingBody += structuring.data.flatTextPostfix;
02967
02968 resultingPart.setBodyEncoded( resultingBody );
02969
02970 }
02971
02972
02973
02974
02975
02976
02977
02978
02979
02980
#ifdef DEBUG
02981
kdDebug(5006) <<
"||| leaving KMComposeWin::processStructuringInfo()\n||| returning: " << bOk << endl;
02982
#endif
02983
02984
return bOk;
02985 }
02986
02987
02988 QCString KMComposeWin::breakLinesAndApplyCodec()
02989 {
02990 QString text;
02991 QCString cText;
02992
02993
if (mDisableBreaking)
02994 text = mEditor->text();
02995
else
02996 text = mEditor->brokenText();
02997
02998 text.truncate(text.length());
02999
03000 {
03001
03002 QString newText;
03003
const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
03004
03005
if (mCharset ==
"us-ascii") {
03006 cText = KMMsgBase::toUsAscii(text);
03007 newText = QString::fromLatin1(cText);
03008 }
else if (codec == 0) {
03009 kdDebug(5006) <<
"Something is wrong and I can not get a codec." << endl;
03010 cText = text.local8Bit();
03011 newText = QString::fromLocal8Bit(cText);
03012 }
else {
03013 cText = codec->fromUnicode(text);
03014 newText = codec->toUnicode(cText);
03015 }
03016
if (cText.isNull()) cText =
"";
03017
03018
if (!text.isEmpty() && (newText != text))
03019 {
03020 QString oldText = mEditor->text();
03021 mEditor->setText(newText);
03022
KCursorSaver idle(KBusyPtr::idle());
03023
bool anyway = (KMessageBox::warningYesNo(
this,
03024 i18n(
"<qt>Not all characters fit into the chosen"
03025
" encoding.<br><br>Send the message anyway?</qt>"),
03026 i18n(
"Some characters will be lost"),
03027 KStdGuiItem::yes(), i18n(
"No, let me change the encoding") ) == KMessageBox::Yes);
03028
if (!anyway)
03029 {
03030 mEditor->setText(oldText);
03031
return QCString();
03032 }
03033 }
03034 }
03035
03036
return cText;
03037 }
03038
03039
03040
03041 QByteArray KMComposeWin::pgpSignedMsg( QCString cText,
03042 StructuringInfoWrapper& structuring,
03043 QCString& signCertFingerprint )
03044 {
03045 QByteArray signature;
03046
03047
03048
if( mSelectedCryptPlug ) {
03049 kdDebug(5006) <<
"\nKMComposeWin::pgpSignedMsg calling CRYPTPLUG "
03050 << mSelectedCryptPlug->libName() << endl;
03051
03052
bool bSign =
true;
03053
03054
if( signCertFingerprint.isEmpty() ) {
03055
03056
if( -1 != mSelectedCryptPlug->libName().find(
"openpgp" ) ) {
03057
03058
03059
03060
const KMIdentity & ident =
03061 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
03062 QCString userKeyId = ident.
pgpIdentity();
03063
if( !userKeyId.isEmpty() ) {
03064 Kpgp::Module *pgp = Kpgp::Module::getKpgp();
03065 Kpgp::Key* key = pgp->publicKey( userKeyId );
03066
if( key ) {
03067 signCertFingerprint = key->primaryFingerprint();
03068 kdDebug(5006) <<
" Signer: " << from()
03069 <<
"\nFingerprint of signature key: "
03070 << QString( signCertFingerprint ) << endl;
03071 }
03072
else {
03073 KMessageBox::sorry(
this,
03074 i18n(
"<qt>This message could not be signed "
03075
"because the OpenPGP key which should be "
03076
"used for signing messages with this "
03077
"identity couldn't be found in your "
03078
"keyring.<br><br>"
03079
"You can change the OpenPGP key "
03080
"which should be used with the current "
03081
"identity in the identity configuration.</qt>"),
03082 i18n(
"Missing Signing Key") );
03083 bSign =
false;
03084 }
03085 }
03086
else {
03087 KMessageBox::sorry(
this,
03088 i18n(
"<qt>This message could not be signed "
03089
"because you didn't define the OpenPGP "
03090
"key which should be used for signing "
03091
"messages with this identity.<br><br>"
03092
"You can define the OpenPGP key "
03093
"which should be used with the current "
03094
"identity in the identity configuration.</qt>"),
03095 i18n(
"Undefined Signing Key") );
03096 bSign =
false;
03097 }
03098 }
03099
else {
03100
int certSize = 0;
03101 QByteArray certificate;
03102 QString selectedCert;
03103 KListBoxDialog dialog( selectedCert,
"", i18n(
"&Select certificate:") );
03104 dialog.resize( 700, 200 );
03105
03106 QCString signer = from().utf8();
03107 signer.replace('\x001',
' ');
03108
03109 kdDebug(5006) <<
"\n\nRetrieving keys for: " << from() << endl;
03110
char* certificatePtr = 0;
03111
bool findCertsOk = mSelectedCryptPlug->findCertificates(
03112 &(*signer),
03113 &certificatePtr,
03114 &certSize,
03115
true )
03116 && (0 < certSize);
03117 kdDebug(5006) <<
"keys retrieved ok: " << findCertsOk << endl;
03118
03119
bool useDialog =
false;
03120
if( findCertsOk ) {
03121 kdDebug(5006) <<
"findCertificates() returned " << certificatePtr << endl;
03122 certificate.assign( certificatePtr, certSize );
03123
03124
03125 dialog.entriesLB->clear();
03126
int iA = 0;
03127
int iZ = 0;
03128
while( iZ < certSize ) {
03129
if( (certificate[iZ] ==
'\1') || (certificate[iZ] ==
'\0') ) {
03130
char c = certificate[iZ];
03131
if( (c ==
'\1') && !useDialog ) {
03132
03133 useDialog =
true;
03134 dialog.setCaption( i18n(
"Select Certificate [%1]")
03135 .arg( from() ) );
03136 }
03137 certificate[iZ] =
'\0';
03138 QString s = QString::fromUtf8( &certificate[iA] );
03139 certificate[iZ] = c;
03140
if( useDialog )
03141 dialog.entriesLB->insertItem( s );
03142
else
03143 selectedCert = s;
03144 ++iZ;
03145 iA = iZ;
03146 }
03147 ++iZ;
03148 }
03149
03150
03151
03152
if( useDialog ) {
03153 dialog.entriesLB->setFocus();
03154 dialog.entriesLB->setSelected( 0,
true );
03155 bSign = (dialog.exec() == QDialog::Accepted);
03156 }
03157
03158
if (bSign) {
03159 signCertFingerprint = selectedCert.utf8();
03160 signCertFingerprint.remove( 0, signCertFingerprint.findRev(
'(' )+1 );
03161 signCertFingerprint.truncate( signCertFingerprint.length()-1 );
03162 kdDebug(5006) <<
"\n\n Signer: " << from()
03163 <<
"\nFingerprint of signature key: " << QString( signCertFingerprint ) <<
"\n\n" << endl;
03164
if( signCertFingerprint.isEmpty() )
03165 bSign =
false;
03166 }
03167 }
03168 }
03169
03170
03171
#ifdef DEBUG
03172
QString ds(
"\n\nBEFORE calling cryptplug:" );
03173 ds +=
"\nstructuring.contentTypeMain: \"";
03174 ds += structuring.data.contentTypeMain;
03175 ds +=
"\"";
03176 ds +=
"\nstructuring.contentTypeVersion:\"";
03177 ds += structuring.data.contentTypeVersion;
03178 ds +=
"\"";
03179 ds +=
"\nstructuring.contentTypeCode: \"";
03180 ds += structuring.data.contentTypeCode;
03181 ds +=
"\"";
03182 ds +=
"\nstructuring.flatTextPrefix: \"";
03183 ds += structuring.data.flatTextPrefix;
03184 ds +=
"\"";
03185 ds +=
"\nstructuring.flatTextSeparator: \"";
03186 ds += structuring.data.flatTextSeparator;
03187 ds +=
"\"";
03188 ds +=
"\nstructuring.flatTextPostfix: \"";
03189 ds += structuring.data.flatTextPostfix;
03190 ds +=
"\"";
03191 kdDebug(5006) << ds << endl;
03192
#endif
03193
03194
03195
03196
03197
if( mSelectedCryptPlug->hasFeature( Feature_WarnSignCertificateExpiry ) ){
03198
int sigDaysLeft = mSelectedCryptPlug->signatureCertificateDaysLeftToExpiry( signCertFingerprint );
03199
if( mSelectedCryptPlug->signatureCertificateExpiryNearWarning() &&
03200 sigDaysLeft <
03201 mSelectedCryptPlug->signatureCertificateExpiryNearInterval() ) {
03202 QString txt1;
03203
if( 0 < sigDaysLeft )
03204 txt1 = i18n(
"The certificate you want to use for signing expires in %1 days.<br>This means that after this period, the recipients will not be able to check your signature any longer." ).arg( sigDaysLeft );
03205
else if( 0 > sigDaysLeft )
03206 txt1 = i18n(
"The certificate you want to use for signing expired %1 days ago.<br>This means that the recipients will not be able to check your signature." ).arg( -sigDaysLeft );
03207
else
03208 txt1 = i18n(
"The certificate you want to use for signing expires today.<br>This means that, starting from tomorrow, the recipients will not be able to check your signature any longer." );
03209
int ret = KMessageBox::warningYesNo(
this,
03210 i18n(
"<qt><p>%1</p>"
03211
"<p>Do you still want to use this "
03212
"certificate?</p></qt>" )
03213 .arg( txt1 ),
03214 i18n(
"Certificate Warning" ),
03215 KGuiItem( i18n(
"&Use Certificate") ),
03216 KGuiItem( i18n(
"&Don't Use Certificate") ) );
03217
if( ret == KMessageBox::No )
03218 bSign =
false;
03219 }
03220
03221
if( bSign && ( 0 <= mSelectedCryptPlug->libName().find(
"smime", 0,
false ) ) ) {
03222
int rootDaysLeft = mSelectedCryptPlug->rootCertificateDaysLeftToExpiry( signCertFingerprint );
03223
if( mSelectedCryptPlug->rootCertificateExpiryNearWarning() &&
03224 rootDaysLeft <
03225 mSelectedCryptPlug->rootCertificateExpiryNearInterval() ) {
03226 QString txt1;
03227
if( 0 < rootDaysLeft )
03228 txt1 = i18n(
"The root certificate of the certificate you want to use for signing expires in %1 days.<br>This means that after this period, the recipients will not be able to check your signature any longer." ).arg( rootDaysLeft );
03229
else if( 0 > rootDaysLeft )
03230 txt1 = i18n(
"The root certificate of the certificate you want to use for signing expired %1 days ago.<br>This means that the recipients will not be able to check your signature." ).arg( -rootDaysLeft );
03231
else
03232 txt1 = i18n(
"The root certificate of the certificate you want to use for signing expires today.<br>This means that beginning from tomorrow, the recipients will not be able to check your signature any longer." );
03233
int ret = KMessageBox::warningYesNo(
this,
03234 i18n(
"<qt><p>%1</p>"
03235
"<p>Do you still want to use this "
03236
"certificate?</p></qt>" )
03237 .arg( txt1 ),
03238 i18n(
"Certificate Warning" ),
03239 KGuiItem( i18n(
"&Use Certificate") ),
03240 KGuiItem( i18n(
"&Don't Use Certificate") ) );
03241
if( ret == KMessageBox::No )
03242 bSign =
false;
03243 }
03244 }
03245
03246
03247
if( bSign && ( 0 <= mSelectedCryptPlug->libName().find(
"smime", 0,
false ) ) ) {
03248
int caDaysLeft = mSelectedCryptPlug->caCertificateDaysLeftToExpiry( signCertFingerprint );
03249
if( mSelectedCryptPlug->caCertificateExpiryNearWarning() &&
03250 caDaysLeft <
03251 mSelectedCryptPlug->caCertificateExpiryNearInterval() ) {
03252 QString txt1;
03253
if( 0 < caDaysLeft )
03254 txt1 = i18n(
"The CA certificate of the certificate you want to use for signing expires in %1 days.<br>This means that after this period, the recipients will not be able to check your signature any longer." ).arg( caDaysLeft );
03255
else if( 0 > caDaysLeft )
03256 txt1 = i18n(
"The CA certificate of the certificate you want to use for signing expired %1 days ago.<br>This means that the recipients will not be able to check your signature." ).arg( -caDaysLeft );
03257
else
03258 txt1 = i18n(
"The CA certificate of the certificate you want to use for signing expires today.<br>This means that beginning from tomorrow, the recipients will not be able to check your signature any longer." );
03259
int ret = KMessageBox::warningYesNo(
this,
03260 i18n(
"<qt><p>%1</p>"
03261
"<p>Do you still want to use this "
03262
"certificate?</p></qt>" )
03263 .arg( txt1 ),
03264 i18n(
"Certificate Warning" ),
03265 KGuiItem( i18n(
"&Use Certificate") ),
03266 KGuiItem( i18n(
"&Don't Use Certificate") ) );
03267
if( ret == KMessageBox::No )
03268 bSign =
false;
03269 }
03270 }
03271 }
03272
03273
03274
if( mSelectedCryptPlug->hasFeature( Feature_WarnSignEmailNotInCertificate ) ) {
03275
if( bSign && mSelectedCryptPlug->warnNoCertificate() &&
03276 !mSelectedCryptPlug->isEmailInCertificate( QString( KMMessage::getEmailAddr( from() ) ).utf8(), signCertFingerprint ) ) {
03277 QString txt1 = i18n(
"The certificate you want to use for signing does not contain your sender email address.<br>This means that it is not possible for the recipients to check whether the email really came from you." );
03278
int ret = KMessageBox::warningYesNo(
this,
03279 i18n(
"<qt><p>%1</p>"
03280
"<p>Do you still want to use this "
03281
"certificate?</p></qt>" )
03282 .arg( txt1 ),
03283 i18n(
"Certificate Warning" ),
03284 KGuiItem( i18n(
"&Use Certificate") ),
03285 KGuiItem( i18n(
"&Don't Use Certificate") ) );
03286
if( ret == KMessageBox::No )
03287 bSign =
false;
03288 }
03289 }
03290 }
03291
03292
03293
03294
if( mSelectedCryptPlug->hasFeature( Feature_SignMessages ) ) {
03295 size_t cipherLen;
03296
03297
const char* cleartext = cText;
03298
char* ciphertext = 0;
03299
03300
if( mDebugComposerCrypto ){
03301 QFile fileS(
"dat_11_sign.input" );
03302
if( fileS.open( IO_WriteOnly ) ) {
03303 QDataStream ds( &fileS );
03304 ds.writeRawBytes( cleartext, strlen( cleartext ) );
03305 fileS.close();
03306 }
03307 }
03308
03309
if ( bSign ){
03310
int errId = 0;
03311
char* errTxt = 0;
03312
if ( mSelectedCryptPlug->signMessage( cleartext,
03313 &ciphertext, &cipherLen,
03314 signCertFingerprint,
03315 structuring,
03316 &errId,
03317 &errTxt ) ){
03318
if( mDebugComposerCrypto ){
03319 QFile fileD(
"dat_12_sign.output" );
03320
if( fileD.open( IO_WriteOnly ) ) {
03321 QDataStream ds( &fileD );
03322 ds.writeRawBytes( ciphertext, cipherLen );
03323 fileD.close();
03324 }
03325 QString ds(
"\nAFTER calling cryptplug:" );
03326 ds +=
"\nstructuring.contentTypeMain: \"";
03327 ds += structuring.data.contentTypeMain;
03328 ds +=
"\"";
03329 ds +=
"\nstructuring.contentTypeVersion:\"";
03330 ds += structuring.data.contentTypeVersion;
03331 ds +=
"\"";
03332 ds +=
"\nstructuring.contentTypeCode: \"";
03333 ds += structuring.data.contentTypeCode;
03334 ds +=
"\"";
03335 ds +=
"\nstructuring.flatTextPrefix: \"";
03336 ds += structuring.data.flatTextPrefix;
03337 ds +=
"\"";
03338 ds +=
"\nstructuring.flatTextSeparator: \"";
03339 ds += structuring.data.flatTextSeparator;
03340 ds +=
"\"";
03341 ds +=
"\nstructuring.flatTextPostfix: \"";
03342 ds += structuring.data.flatTextPostfix;
03343 ds +=
"\"";
03344 ds +=
"\n\nresulting signature bloc:\n\"";
03345 ds += ciphertext;
03346 ds +=
"\"\n\n";
03347 ds +=
"signature length: ";
03348 ds += cipherLen;
03349 kdDebug(5006) << ds << endl << endl;
03350 }
03351 signature.assign( ciphertext, cipherLen );
03352 }
else if ( errId == 20 ) {
03353
return false;
03354 }
else {
03355 QString error(
"#");
03356 error += QString::number( errId );
03357 error +=
" : ";
03358
if( errTxt )
03359 error += errTxt;
03360
else
03361 error += i18n(
"[unknown error]");
03362 KMessageBox::sorry(
this,
03363 i18n(
"<qt><p><b>This message could not be signed!</b></p>"
03364
"<p>The Crypto Plug-In '%1' reported the following "
03365
"details:</p>"
03366
"<p><i>%2</i></p>"
03367
"<p>Your configuration might be invalid or the Plug-In "
03368
"damaged.</p>"
03369
"<p><b>Please contact your system "
03370
"administrator.</b></p></qt>")
03371 .arg(mSelectedCryptPlug->libName())
03372 .arg( error ) );
03373 }
03374
03375
03376
delete errTxt;
03377 errTxt = 0;
03378 }
03379 }
03380
03381
03382
03383
03384
03385
03386
03387 kdDebug(5006) <<
"\nKMComposeWin::pgpSignedMsg returning from CRYPTPLUG.\n" << endl;
03388 }
else
03389 KMessageBox::sorry(
this,
03390 i18n(
"<qt>No active Crypto Plug-In could be found.<br><br>"
03391
"Please activate a Plug-In in the configuration dialog.</qt>"));
03392
return signature;
03393 }
03394
03395
03396
03397 Kpgp::Result KMComposeWin::pgpEncryptedMsg( QByteArray & encryptedBody,
03398 QCString cText,
03399 StructuringInfoWrapper& structuring,
03400 QCString& encryptCertFingerprints )
03401 {
03402 Kpgp::Result result = Kpgp::Ok;
03403
03404
03405
if( mSelectedCryptPlug ) {
03406 kdDebug(5006) <<
"\nKMComposeWin::pgpEncryptedMsg: going to call CRYPTPLUG "
03407 << mSelectedCryptPlug->libName() << endl;
03408
03409
03410
#if 0
03411
03412
03413
03414
03415
03416
03417
03418
if( encryptCertFingerprints.isEmpty() &&
03419 mSelectedCryptPlug->hasFeature( Feature_WarnEncryptCertificateExpiry ) &&
03420 mSelectedCryptPlug->hasFeature( Feature_EncryptionCRLs ) ) {
03421
int crlDaysLeft = mSelectedCryptPlug->encryptionCRLsDaysLeftToExpiry();
03422
if( mSelectedCryptPlug->encryptionUseCRLs() &&
03423 mSelectedCryptPlug->encryptionCRLExpiryNearWarning() &&
03424 crlDaysLeft <
03425 mSelectedCryptPlug->encryptionCRLNearExpiryInterval() ) {
03426
int ret = KMessageBox::warningYesNo(
this,
03427 i18n(
"<qt><p>The certification revocation lists, that "
03428
"are used for checking the validity of the "
03429
"certificate you want to use for encrypting, "
03430
"expire in %1 days.</p>"
03431
"<p>Do you still want to encrypt this message?"
03432
"</p></qt>" )
03433 .arg( crlDaysLeft ),
03434 i18n(
"Certificate Warning" ),
03435 KGuiItem( i18n(
"&Encrypt" ) ),
03436 KGuiItem( i18n(
"&Don't Encrypt" ) ) );
03437
if( ret == KMessageBox::No )
03438
return Kpgp::Canceled;
03439 }
03440 }
03441
#endif
03442
03443
03444
03445
const char* cleartext = cText;
03446
const char* ciphertext = 0;
03447
03448
03449 size_t cipherLen;
03450
03451
int errId = 0;
03452
char* errTxt = 0;
03453
if( mSelectedCryptPlug->hasFeature( Feature_EncryptMessages ) &&
03454 mSelectedCryptPlug->encryptMessage( cleartext,
03455 &ciphertext, &cipherLen,
03456 encryptCertFingerprints,
03457 structuring,
03458 &errId,
03459 &errTxt )
03460 && ciphertext )
03461 encryptedBody.assign( ciphertext, cipherLen );
03462
else {
03463 QString error(
"#");
03464 error += QString::number( errId );
03465 error +=
" : ";
03466
if( errTxt )
03467 error += errTxt;
03468
else
03469 error += i18n(
"[unknown error]");
03470 KMessageBox::sorry(
this,
03471 i18n(
"<qt><p><b>This message could not be encrypted!</b></p>"
03472
"<p>The Crypto Plug-In '%1' reported the following "
03473
"details:</p>"
03474
"<p><i>%2</i></p>"
03475
"<p>Your configuration might be invalid or the Plug-In "
03476
"damaged.</p>"
03477
"<p><b>Please contact your system "
03478
"administrator.</b></p></qt>")
03479 .arg(mSelectedCryptPlug->libName())
03480 .arg( error ) );
03481 }
03482
delete errTxt;
03483 errTxt = 0;
03484
03485
03486
03487
03488 kdDebug(5006) <<
"\nKMComposeWin::pgpEncryptedMsg: returning from CRYPTPLUG.\n" << endl;
03489
03490 }
else
03491 KMessageBox::sorry(
this,
03492 i18n(
"<qt>No active Crypto Plug-In could be found.<br><br>"
03493
"Please activate a Plug-In in the configuration dialog.</qt>"));
03494
03495
return result;
03496 }
03497
03498
03499
03500 QCString
03501 KMComposeWin::getEncryptionCertificate(
const QString& recipient )
03502 {
03503
bool bEncrypt =
true;
03504
03505 QCString addressee = recipient.utf8();
03506 addressee.replace('\x001',
' ');
03507 kdDebug(5006) <<
"\n\n1st try: Retrieving keys for: " << recipient << endl;
03508
03509
03510 QString selectedCert;
03511 KListBoxDialog dialog( selectedCert,
"", i18n(
"&Select certificate:" ) );
03512 dialog.resize( 700, 200 );
03513
bool useDialog;
03514
int certSize = 0;
03515 QByteArray certificateList;
03516
03517
bool askForDifferentSearchString =
false;
03518
do {
03519
03520 certSize = 0;
03521
char* certificatePtr = 0;
03522
bool findCertsOk;
03523
if( askForDifferentSearchString )
03524 findCertsOk =
false;
03525
else {
03526 findCertsOk = mSelectedCryptPlug->findCertificates( &(*addressee),
03527 &certificatePtr,
03528 &certSize,
03529
false )
03530 && (0 < certSize);
03531 kdDebug(5006) <<
" keys retrieved successfully: " << findCertsOk <<
"\n" << endl;
03532 kdDebug(5006) <<
"findCertificates() 1st try returned " << certificatePtr << endl;
03533
if( findCertsOk )
03534 certificateList.assign( certificatePtr, certSize );
03535 }
03536
while( !findCertsOk ) {
03537
bool bOk =
false;
03538 addressee = KInputDialog::getText(
03539 askForDifferentSearchString
03540 ? i18n(
"Look for Other Certificates")
03541 : i18n(
"No Certificate Found"),
03542 i18n(
"Enter different address for recipient %1 "
03543
"or enter \" * \" to see all certificates:")
03544 .arg(recipient),
03545 addressee, &bOk,
this )
03546 .stripWhiteSpace().utf8();
03547 askForDifferentSearchString =
false;
03548
if( bOk ) {
03549 addressee = addressee.simplifyWhiteSpace();
03550
if( (
"\"*\"" == addressee) ||
03551 (
"\" *\"" == addressee) ||
03552 (
"\"* \"" == addressee) ||
03553 (
"\" * \"" == addressee))
03554 addressee =
"*";
03555 kdDebug(5006) <<
"\n\nnext try: Retrieving keys for: " << addressee << endl;
03556 certSize = 0;
03557
char* certificatePtr = 0;
03558 findCertsOk = mSelectedCryptPlug->findCertificates(
03559 &(*addressee),
03560 &certificatePtr,
03561 &certSize,
03562
false )
03563 && (0 < certSize);
03564 kdDebug(5006) <<
" keys retrieved successfully: " << findCertsOk <<
"\n" << endl;
03565 kdDebug(5006) <<
"findCertificates() 2nd try returned " << certificatePtr << endl;
03566
if( findCertsOk )
03567 certificateList.assign( certificatePtr, certSize );
03568 }
else {
03569 bEncrypt =
false;
03570
break;
03571 }
03572 }
03573
if( bEncrypt && findCertsOk ) {
03574
03575
03576 dialog.entriesLB->clear();
03577
03578
03579
bool bAlwaysShowDialog =
true;
03580
03581 useDialog =
false;
03582
int iA = 0;
03583
int iZ = 0;
03584
while( iZ < certSize ) {
03585
if( (certificateList.at(iZ) ==
'\1') || (certificateList.at(iZ) ==
'\0') ) {
03586 kdDebug(5006) <<
"iA=" << iA <<
" iZ=" << iZ << endl;
03587
char c = certificateList.at(iZ);
03588
if( (bAlwaysShowDialog || (c ==
'\1')) && !useDialog ) {
03589
03590 useDialog =
true;
03591 dialog.setCaption( i18n(
"Select Certificate for Encryption [%1]" )
03592 .arg( recipient ) );
03593 dialog.setLabelAbove(
03594 i18n(
"&Select certificate for recipient %1:" )
03595 .arg( recipient ) );
03596 }
03597 certificateList.at(iZ) =
'\0';
03598 QString s = QString::fromUtf8( &certificateList.at(iA) );
03599 certificateList.at(iZ) = c;
03600
if( useDialog )
03601 dialog.entriesLB->insertItem( s );
03602
else
03603 selectedCert = s;
03604 ++iZ;
03605 iA = iZ;
03606 }
03607 ++iZ;
03608 }
03609
03610
03611
if( useDialog ) {
03612 dialog.setCommentBelow(
03613 i18n(
"(Certificates matching address \"%1\", "
03614
"press [Cancel] to use different address for recipient %2.)")
03615 .arg( addressee )
03616 .arg( recipient ) );
03617 dialog.entriesLB->setFocus();
03618 dialog.entriesLB->setSelected( 0,
true );
03619 askForDifferentSearchString = (dialog.exec() != QDialog::Accepted);
03620 }
03621 }
03622 }
while ( askForDifferentSearchString );
03623
03624
if( bEncrypt )
03625
return selectedCert.utf8();
03626
else
03627
return QCString();
03628 }
03629
03630
03631
bool KMComposeWin::checkForEncryptCertificateExpiry(
const QString& recipient,
03632
const QCString& certFingerprint )
03633 {
03634
bool bEncrypt =
true;
03635
03636
03637
03638
if( mSelectedCryptPlug->hasFeature( Feature_WarnEncryptCertificateExpiry ) ) {
03639 QString captionWarn = i18n(
"Certificate Warning [%1]" ).arg( recipient );
03640
03641
int encRecvDaysLeft =
03642 mSelectedCryptPlug->receiverCertificateDaysLeftToExpiry( certFingerprint );
03643
if( mSelectedCryptPlug->receiverCertificateExpiryNearWarning() &&
03644 encRecvDaysLeft <
03645 mSelectedCryptPlug->receiverCertificateExpiryNearWarningInterval() ) {
03646 QString txt1;
03647
if( 0 < encRecvDaysLeft )
03648 txt1 = i18n(
"The certificate of the recipient you want to send this "
03649
"message to expires in %1 days.<br>This means that after "
03650
"this period, the recipient will not be able to read "
03651
"your message any longer." )
03652 .arg( encRecvDaysLeft );
03653
else if( 0 > encRecvDaysLeft )
03654 txt1 = i18n(
"The certificate of the recipient you want to send this "
03655
"message to expired %1 days ago.<br>This means that the "
03656
"recipient will not be able to read your message." )
03657 .arg( -encRecvDaysLeft );
03658
else
03659 txt1 = i18n(
"The certificate of the recipient you want to send this "
03660
"message to expires today.<br>This means that beginning "
03661
"from tomorrow, the recipient will not be able to read "
03662
"your message any longer." );
03663
int ret = KMessageBox::warningYesNo(
this,
03664 i18n(
"<qt><p>%1</p>"
03665
"<p>Do you still want to use "
03666
"this certificate?</p></qt>" )
03667 .arg( txt1 ),
03668 captionWarn,
03669 KGuiItem( i18n(
"&Use Certificate") ),
03670 KGuiItem( i18n(
"&Don't Use Certificate") ) );
03671
if( ret == KMessageBox::No )
03672 bEncrypt =
false;
03673 }
03674
03675
if( bEncrypt ) {
03676
int certInChainDaysLeft =
03677 mSelectedCryptPlug->certificateInChainDaysLeftToExpiry( certFingerprint );
03678
if( mSelectedCryptPlug->certificateInChainExpiryNearWarning() &&
03679 certInChainDaysLeft <
03680 mSelectedCryptPlug->certificateInChainExpiryNearWarningInterval() ) {
03681 QString txt1;
03682
if( 0 < certInChainDaysLeft )
03683 txt1 = i18n(
"One of the certificates in the chain of the "
03684
"certificate of the recipient you want to send this "
03685
"message to expires in %1 days.<br>"
03686
"This means that after this period, the recipient "
03687
"might not be able to read your message any longer." )
03688 .arg( certInChainDaysLeft );
03689
else if( 0 > certInChainDaysLeft )
03690 txt1 = i18n(
"One of the certificates in the chain of the "
03691
"certificate of the recipient you want to send this "
03692
"message to expired %1 days ago.<br>"
03693
"This means that the recipient might not be able to "
03694
"read your message." )
03695 .arg( -certInChainDaysLeft );
03696
else
03697 txt1 = i18n(
"One of the certificates in the chain of the "
03698
"certificate of the recipient you want to send this "
03699
"message to expires today.<br>This means that "
03700
"beginning from tomorrow, the recipient might not be "
03701
"able to read your message any longer." );
03702
int ret = KMessageBox::warningYesNo(
this,
03703 i18n(
"<qt><p>%1</p>"
03704
"<p>Do you still want to use this "
03705
"certificate?</p></qt>" )
03706 .arg( txt1 ),
03707 captionWarn,
03708 KGuiItem( i18n(
"&Use Certificate") ),
03709 KGuiItem( i18n(
"&Don't Use Certificate") ) );
03710
if( ret == KMessageBox::No )
03711 bEncrypt =
false;
03712 }
03713 }
03714
03715
03716
03717
03718
03719
03720
03721
03722
03723
03724
03725
03726
03727
03728
03729
03730
03731 }
03732
03733
return bEncrypt;
03734 }
03735
03736
03737
03738
void KMComposeWin::addAttach(
const KURL aUrl)
03739 {
03740
if ( !aUrl.isValid() ) {
03741 KMessageBox::sorry(
this, i18n(
"<qt><p>KMail couldn't recognize the location of the attachment (%1).</p>"
03742
"<p>You have to specify the full path if you wish to attach a file.</p></qt>" )
03743 .arg( aUrl.prettyURL() ) );
03744
return;
03745 }
03746 KIO::TransferJob *job = KIO::get(aUrl);
03747 KIO::Scheduler::scheduleJob( job );
03748 atmLoadData ld;
03749 ld.url = aUrl;
03750 ld.data = QByteArray();
03751 ld.insert =
false;
03752 mMapAtmLoadData.insert(job, ld);
03753 connect(job, SIGNAL(result(KIO::Job *)),
03754
this, SLOT(slotAttachFileResult(KIO::Job *)));
03755 connect(job, SIGNAL(data(KIO::Job *,
const QByteArray &)),
03756
this, SLOT(slotAttachFileData(KIO::Job *,
const QByteArray &)));
03757 }
03758
03759
03760
03761
void KMComposeWin::addAttach(
const KMMessagePart* msgPart)
03762 {
03763 mAtmList.append(msgPart);
03764
03765
03766
if (mAtmList.count()==1)
03767 {
03768 mGrid->setRowStretch(mNumHeaders+1, 50);
03769 mAtmListView->setMinimumSize(100, 80);
03770 mAtmListView->setMaximumHeight( 100 );
03771 mAtmListView->show();
03772 resize(size());
03773 }
03774
03775
03776 KMAtmListViewItem *lvi =
new KMAtmListViewItem( mAtmListView );
03777 msgPartToItem(msgPart, lvi);
03778 mAtmItemList.append(lvi);
03779
03780 slotUpdateAttachActions();
03781 }
03782
03783
03784
03785
void KMComposeWin::slotUpdateAttachActions()
03786 {
03787
int selectedCount = 0;
03788
for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it ) {
03789
if ( (*it)->isSelected() ) {
03790 ++selectedCount;
03791 }
03792 }
03793
03794 mAttachRemoveAction->setEnabled( selectedCount >= 1 );
03795 mAttachSaveAction->setEnabled( selectedCount == 1 );
03796 mAttachPropertiesAction->setEnabled( selectedCount == 1 );
03797 }
03798
03799
03800
03801
03802 QString KMComposeWin::prettyMimeType(
const QString& type )
03803 {
03804 QString t = type.lower();
03805 KServiceType::Ptr st = KServiceType::serviceType( t );
03806
return st ? st->comment() : t;
03807 }
03808
03809
void KMComposeWin::msgPartToItem(
const KMMessagePart* msgPart,
03810 KMAtmListViewItem *lvi)
03811 {
03812 assert(msgPart != 0);
03813
03814
if (!msgPart->fileName().isEmpty())
03815 lvi->setText(0, msgPart->fileName());
03816
else
03817 lvi->setText(0, msgPart->name());
03818 lvi->setText(1, KIO::convertSize( msgPart->decodedSize()));
03819 lvi->setText(2, msgPart->contentTransferEncodingStr());
03820 lvi->setText(3, prettyMimeType(msgPart->typeStr() +
"/" + msgPart->subtypeStr()));
03821
if( mSelectedCryptPlug ) {
03822 lvi->enableCryptoCBs(
true );
03823 lvi->setEncrypt( mEncryptAction->isChecked() );
03824 lvi->setSign( mSignAction->isChecked() );
03825 }
else {
03826 lvi->enableCryptoCBs(
false );
03827 }
03828 }
03829
03830
03831
03832
void KMComposeWin::removeAttach(
const QString &aUrl)
03833 {
03834
int idx;
03835 KMMessagePart* msgPart;
03836
for(idx=0,msgPart=mAtmList.first(); msgPart;
03837 msgPart=mAtmList.next(),idx++) {
03838
if (msgPart->name() == aUrl) {
03839 removeAttach(idx);
03840
return;
03841 }
03842 }
03843 }
03844
03845
03846
03847
void KMComposeWin::removeAttach(
int idx)
03848 {
03849 mAtmModified = TRUE;
03850 mAtmList.remove(idx);
03851
delete mAtmItemList.take(idx);
03852
03853
if( mAtmList.isEmpty() )
03854 {
03855 mAtmListView->hide();
03856 mGrid->setRowStretch(mNumHeaders+1, 0);
03857 mAtmListView->setMinimumSize(0, 0);
03858 resize(size());
03859 }
03860 }
03861
03862
03863
03864
bool KMComposeWin::encryptFlagOfAttachment(
int idx)
03865 {
03866
return (
int)(mAtmItemList.count()) > idx
03867 ? ((KMAtmListViewItem*)(mAtmItemList.at( idx )))->isEncrypt()
03868 : false;
03869 }
03870
03871
03872
03873
bool KMComposeWin::signFlagOfAttachment(
int idx)
03874 {
03875
return (
int)(mAtmItemList.count()) > idx
03876 ? ((KMAtmListViewItem*)(mAtmItemList.at( idx )))->isSign()
03877 : false;
03878 }
03879
03880
03881
03882
void KMComposeWin::addrBookSelInto()
03883 {
03884 AddressesDialog dlg(
this );
03885 QString txt;
03886 QStringList lst;
03887
03888 txt = mEdtTo->text().stripWhiteSpace();
03889
if ( !txt.isEmpty() ) {
03890 lst = KMMessage::splitEmailAddrList( txt );
03891 dlg.setSelectedTo( lst );
03892 }
03893
03894 txt = mEdtCc->text().stripWhiteSpace();
03895
if ( !txt.isEmpty() ) {
03896 lst = KMMessage::splitEmailAddrList( txt );
03897 dlg.setSelectedCC( lst );
03898 }
03899
03900 txt = mEdtBcc->text().stripWhiteSpace();
03901
if ( !txt.isEmpty() ) {
03902 lst = KMMessage::splitEmailAddrList( txt );
03903 dlg.setSelectedBCC( lst );
03904 }
03905
03906 dlg.setRecentAddresses( RecentAddresses::self( KMKernel::config() )->kabcAddresses() );
03907
03908
if (dlg.exec()==QDialog::Rejected)
return;
03909
03910 mEdtTo->setText( dlg.to().join(
", ") );
03911 mEdtTo->setEdited(
true );
03912
03913 mEdtCc->setText( dlg.cc().join(
", ") );
03914 mEdtCc->setEdited(
true );
03915
03916 mEdtBcc->setText( dlg.bcc().join(
", ") );
03917 mEdtBcc->setEdited(
true );
03918 }
03919
03920
03921
03922
void KMComposeWin::setCharset(
const QCString& aCharset,
bool forceDefault)
03923 {
03924
if ((forceDefault && mForceReplyCharset) || aCharset.isEmpty())
03925 mCharset = mDefCharset;
03926
else
03927 mCharset = aCharset.lower();
03928
03929
if ( mCharset.isEmpty() || mCharset ==
"default" )
03930 mCharset = mDefCharset;
03931
03932
if (mAutoCharset)
03933 {
03934 mEncodingAction->setCurrentItem( 0 );
03935
return;
03936 }
03937
03938 QStringList encodings = mEncodingAction->items();
03939
int i = 0;
03940
bool charsetFound = FALSE;
03941
for ( QStringList::Iterator it = encodings.begin(); it != encodings.end();
03942 ++it, i++ )
03943 {
03944
if (i > 0 && ((mCharset ==
"us-ascii" && i == 1) ||
03945 (i != 1 && KGlobal::charsets()->codecForName(
03946 KGlobal::charsets()->encodingForName(*it))
03947 == KGlobal::charsets()->codecForName(mCharset))))
03948 {
03949 mEncodingAction->setCurrentItem( i );
03950 slotSetCharset();
03951 charsetFound = TRUE;
03952
break;
03953 }
03954 }
03955
if (!aCharset.isEmpty() && !charsetFound) setCharset(
"", TRUE);
03956 }
03957
03958
03959
03960
void KMComposeWin::slotAddrBook()
03961 {
03962 KMAddrBookExternal::openAddressBook(
this);
03963 }
03964
03965
03966
03967
void KMComposeWin::slotAddrBookFrom()
03968 {
03969 addrBookSelInto();
03970 }
03971
03972
03973
03974
void KMComposeWin::slotAddrBookReplyTo()
03975 {
03976 addrBookSelInto();
03977 }
03978
03979
03980
03981
void KMComposeWin::slotAddrBookTo()
03982 {
03983 addrBookSelInto();
03984 }
03985
03986
03987
void KMComposeWin::slotAttachFile()
03988 {
03989
03990
03991
03992
03993 KURL::List files = KFileDialog::getOpenURLs(QString::null, QString::null,
03994
this, i18n(
"Attach File"));
03995
for (KURL::List::Iterator it = files.begin(); it != files.end(); ++it)
03996 addAttach(*it);
03997 }
03998
03999
04000
04001
void KMComposeWin::slotAttachFileData(KIO::Job *job,
const QByteArray &data)
04002 {
04003 QMap<KIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
04004 assert(it != mMapAtmLoadData.end());
04005 QBuffer buff((*it).data);
04006 buff.open(IO_WriteOnly | IO_Append);
04007 buff.writeBlock(data.data(), data.size());
04008 buff.close();
04009 }
04010
04011
04012
04013
void KMComposeWin::slotAttachFileResult(KIO::Job *job)
04014 {
04015 QMap<KIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
04016 assert(it != mMapAtmLoadData.end());
04017
if (job->error())
04018 {
04019 mMapAtmLoadData.remove(it);
04020 job->showErrorDialog();
04021
return;
04022 }
04023
if ((*it).insert)
04024 {
04025 (*it).data.resize((*it).data.size() + 1);
04026 (*it).data[(*it).data.size() - 1] =
'\0';
04027
if (
const QTextCodec * codec = KGlobal::charsets()->codecForName((*it).encoding) )
04028 mEditor->insert( codec->toUnicode( (*it).data ) );
04029
else
04030 mEditor->insert( QString::fromLocal8Bit( (*it).data ) );
04031 mMapAtmLoadData.remove(it);
04032
return;
04033 }
04034 QString name;
04035 QString urlStr = (*it).url.prettyURL();
04036 KMMessagePart* msgPart;
04037
int i;
04038
04039
KCursorSaver busy(KBusyPtr::busy());
04040
04041
04042 QString mimeType = static_cast<KIO::MimetypeJob*>(job)->mimetype();
04043
04044 i = urlStr.findRev(
'/');
04045
if( i == -1 )
04046 name = urlStr;
04047
else if( i + 1 < int( urlStr.length() ) )
04048 name = urlStr.mid( i + 1, 256 );
04049
else {
04050
04051
04052
if( mimeType ==
"text/html" )
04053 name =
"index.html";
04054
else {
04055
04056 QStringList patterns( KMimeType::mimeType( mimeType )->patterns() );
04057 QString ext;
04058
if( !patterns.isEmpty() ) {
04059 ext = patterns[0];
04060
int i = ext.findRev(
'.' );
04061
if( i == -1 )
04062 ext.prepend(
'.' );
04063
else if( i > 0 )
04064 ext = ext.mid( i );
04065 }
04066 name = QString(
"unknown") += ext;
04067 }
04068 }
04069
04070 QCString encoding = KMMsgBase::autoDetectCharset(mCharset,
04071 KMMessage::preferredCharsets(), name);
04072
if (encoding.isEmpty()) encoding =
"utf-8";
04073 QCString encName = KMMsgBase::encodeRFC2231String(name, encoding);
04074
bool RFC2231encoded = name != QString(encName);
04075
04076
04077 msgPart =
new KMMessagePart;
04078 msgPart->setName(name);
04079 QValueList<int> allowedCTEs;
04080 msgPart->setBodyAndGuessCte((*it).data, allowedCTEs,
04081 !kmkernel->msgSender()->sendQuotedPrintable());
04082 kdDebug(5006) <<
"autodetected cte: " << msgPart->cteStr() << endl;
04083
int slash = mimeType.find(
'/' );
04084
if( slash == -1 )
04085 slash = mimeType.length();
04086 msgPart->setTypeStr( mimeType.left( slash ).latin1() );
04087 msgPart->setSubtypeStr( mimeType.mid( slash + 1 ).latin1() );
04088 msgPart->setContentDisposition(QCString(
"attachment;\n\tfilename")
04089 + ((RFC2231encoded) ?
"*" :
"") +
"=\"" + encName +
"\"");
04090
04091 mMapAtmLoadData.remove(it);
04092
04093 msgPart->setCharset(mCharset);
04094
04095
04096 KConfigGroup composer(KMKernel::config(),
"Composer");
04097
if (!composer.hasKey(
"showMessagePartDialogOnAttach"))
04098
04099 composer.writeEntry(
"showMessagePartDialogOnAttach",
false);
04100
if (composer.readBoolEntry(
"showMessagePartDialogOnAttach",
false)) {
04101
KMMsgPartDialogCompat dlg;
04102
int encodings = 0;
04103
for ( QValueListConstIterator<int> it = allowedCTEs.begin() ;
04104 it != allowedCTEs.end() ; ++it )
04105
switch ( *it ) {
04106
case DwMime::kCteBase64: encodings |= KMMsgPartDialog::Base64;
break;
04107
case DwMime::kCteQp: encodings |= KMMsgPartDialog::QuotedPrintable;
break;
04108
case DwMime::kCte7bit: encodings |= KMMsgPartDialog::SevenBit;
break;
04109
case DwMime::kCte8bit: encodings |= KMMsgPartDialog::EightBit;
break;
04110
default: ;
04111 }
04112 dlg.
setShownEncodings( encodings );
04113 dlg.
setMsgPart(msgPart);
04114
if (!dlg.exec()) {
04115
delete msgPart;
04116 msgPart = 0;
04117
return;
04118 }
04119 }
04120 mAtmModified = TRUE;
04121
if (msgPart->typeStr().lower() !=
"text") msgPart->setCharset(QCString());
04122
04123
04124 addAttach(msgPart);
04125 }
04126
04127
04128
04129
void KMComposeWin::slotInsertFile()
04130 {
04131 KFileDialog fdlg(QString::null, QString::null,
this, 0, TRUE);
04132 fdlg.setCaption(i18n(
"Insert File"));
04133 fdlg.toolBar()->insertCombo(KMMsgBase::supportedEncodings(FALSE), 4711,
04134
false, 0, 0, 0);
04135 KComboBox *combo = fdlg.toolBar()->getCombo(4711);
04136
for (
int i = 0; i < combo->count(); i++)
04137
if (KGlobal::charsets()->codecForName(KGlobal::charsets()->
04138 encodingForName(combo->text(i)))
04139 == QTextCodec::codecForLocale()) combo->setCurrentItem(i);
04140
if (!fdlg.exec())
return;
04141
04142 KURL u = fdlg.selectedURL();
04143
04144
if (u.fileName().isEmpty())
return;
04145
04146 KIO::Job *job = KIO::get(u);
04147 atmLoadData ld;
04148 ld.url = u;
04149 ld.data = QByteArray();
04150 ld.insert =
true;
04151 ld.encoding = KGlobal::charsets()->encodingForName(
04152 combo->currentText()).latin1();
04153 mMapAtmLoadData.insert(job, ld);
04154 connect(job, SIGNAL(result(KIO::Job *)),
04155
this, SLOT(slotAttachFileResult(KIO::Job *)));
04156 connect(job, SIGNAL(data(KIO::Job *,
const QByteArray &)),
04157
this, SLOT(slotAttachFileData(KIO::Job *,
const QByteArray &)));
04158 }
04159
04160
04161
04162
void KMComposeWin::slotSetCharset()
04163 {
04164
if (mEncodingAction->currentItem() == 0)
04165 {
04166 mAutoCharset =
true;
04167
return;
04168 }
04169 mAutoCharset =
false;
04170
04171 mCharset = KGlobal::charsets()->encodingForName( mEncodingAction->
04172 currentText() ).latin1();
04173 }
04174
04175
04176
04177
void KMComposeWin::slotSelectCryptoModule()
04178 {
04179 mSelectedCryptPlug = 0;
04180
int sel = mCryptoModuleAction->currentItem();
04181
int i = 1;
04182
for ( CryptPlugWrapperListIterator it( *(kmkernel->cryptPlugList()) ) ;
04183 it.current() ;
04184 ++it, ++i )
04185
if( i == sel ){
04186 mSelectedCryptPlug = it.current();
04187
break;
04188 }
04189
if( mSelectedCryptPlug ) {
04190
04191
if( 0 == mAtmListView->columnWidth( mAtmColEncrypt ) ) {
04192
04193
04194
if( !mAtmList.isEmpty() ) {
04195
for( KMAtmListViewItem* lvi = (KMAtmListViewItem*)mAtmItemList.first();
04196 lvi;
04197 lvi = (KMAtmListViewItem*)mAtmItemList.next() ) {
04198 lvi->setSign( mSignAction->isChecked() );
04199 lvi->setEncrypt( mEncryptAction->isChecked() );
04200 }
04201 }
04202
int totalWidth = 0;
04203
04204
for(
int col=0; col < mAtmColEncrypt; col++ )
04205 totalWidth += mAtmListView->columnWidth( col );
04206
int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
04207 - mAtmSignColWidth;
04208
04209
04210
int usedWidth = 0;
04211
for(
int col=0; col < mAtmColEncrypt-1; col++ ) {
04212
int newWidth = mAtmListView->columnWidth( col ) * reducedTotalWidth
04213 / totalWidth;
04214 mAtmListView->setColumnWidth( col, newWidth );
04215 usedWidth += newWidth;
04216 }
04217
04218
04219
04220 mAtmListView->setColumnWidth( mAtmColEncrypt-1,
04221 reducedTotalWidth - usedWidth );
04222 mAtmListView->setColumnWidth( mAtmColEncrypt, mAtmEncryptColWidth );
04223 mAtmListView->setColumnWidth( mAtmColSign, mAtmSignColWidth );
04224
for( KMAtmListViewItem* lvi = (KMAtmListViewItem*)mAtmItemList.first();
04225 lvi;
04226 lvi = (KMAtmListViewItem*)mAtmItemList.next() ) {
04227 lvi->enableCryptoCBs(
true );
04228 }
04229 }
04230 }
else {
04231
04232
if( 0 != mAtmListView->columnWidth( mAtmColEncrypt ) ) {
04233 mAtmEncryptColWidth = mAtmListView->columnWidth( mAtmColEncrypt );
04234 mAtmSignColWidth = mAtmListView->columnWidth( mAtmColSign );
04235
int totalWidth = 0;
04236
04237
for(
int col=0; col < mAtmListView->columns(); col++ )
04238 totalWidth += mAtmListView->columnWidth( col );
04239
int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
04240 - mAtmSignColWidth;
04241
04242
04243
int usedWidth = 0;
04244
for(
int col=0; col < mAtmColEncrypt-1; col++ ) {
04245
int newWidth = mAtmListView->columnWidth( col ) * totalWidth
04246 / reducedTotalWidth;
04247 mAtmListView->setColumnWidth( col, newWidth );
04248 usedWidth += newWidth;
04249 }
04250
04251
04252
04253 mAtmListView->setColumnWidth( mAtmColEncrypt-1, totalWidth - usedWidth );
04254 mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
04255 mAtmListView->setColumnWidth( mAtmColSign, 0 );
04256
for( KMAtmListViewItem* lvi = (KMAtmListViewItem*)mAtmItemList.first();
04257 lvi;
04258 lvi = (KMAtmListViewItem*)mAtmItemList.next() ) {
04259 lvi->enableCryptoCBs(
false );
04260 }
04261 }
04262 }
04263 }
04264
04265
04266
04267
void KMComposeWin::slotInsertMyPublicKey()
04268 {
04269 KMMessagePart* msgPart;
04270
04271
KCursorSaver busy(KBusyPtr::busy());
04272
04273
04274 QCString pgpUserId =
04275 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() ).pgpIdentity();
04276
04277 QCString armoredKey = Kpgp::Module::getKpgp()->getAsciiPublicKey(pgpUserId);
04278
if (armoredKey.isEmpty())
04279 {
04280
KCursorSaver idle(KBusyPtr::idle());
04281 KMessageBox::sorry(
this, i18n(
"Unable to obtain your public key.") );
04282
return;
04283 }
04284
04285
04286 msgPart =
new KMMessagePart;
04287 msgPart->setName(i18n(
"My OpenPGP key"));
04288 msgPart->setTypeStr(
"application");
04289 msgPart->setSubtypeStr(
"pgp-keys");
04290 QValueList<int> dummy;
04291 msgPart->setBodyAndGuessCte(armoredKey, dummy,
false);
04292 msgPart->setContentDisposition(
"attachment;\n\tfilename=public_key.asc");
04293
04294
04295 addAttach(msgPart);
04296 rethinkFields();
04297 }
04298
04299
04300
void KMComposeWin::slotInsertPublicKey()
04301 {
04302 QCString keyID;
04303 KMMessagePart* msgPart;
04304 Kpgp::Module *pgp;
04305
04306
if ( !(pgp = Kpgp::Module::getKpgp()) )
04307
return;
04308
04309 keyID = pgp->selectPublicKey( i18n(
"Attach Public OpenPGP Key"),
04310 i18n(
"Select the public key which should "
04311
"be attached.") );
04312
04313
if (keyID.isEmpty())
04314
return;
04315
04316 QCString armoredKey = pgp->getAsciiPublicKey(keyID);
04317
if (!armoredKey.isEmpty()) {
04318
04319 msgPart =
new KMMessagePart;
04320 msgPart->setName(i18n(
"OpenPGP key 0x%1").arg(keyID));
04321 msgPart->setTypeStr(
"application");
04322 msgPart->setSubtypeStr(
"pgp-keys");
04323 QValueList<int> dummy;
04324 msgPart->setBodyAndGuessCte(armoredKey, dummy,
false);
04325 msgPart->setContentDisposition(
"attachment;\n\tfilename=0x" + keyID +
".asc");
04326
04327
04328 addAttach(msgPart);
04329 rethinkFields();
04330 }
else {
04331 KMessageBox::sorry(
this,
04332 i18n(
"Unable to obtain the selected public key." ) );
04333 }
04334 }
04335
04336
04337
04338
void KMComposeWin::slotAttachPopupMenu(QListViewItem *,
const QPoint &,
int)
04339 {
04340
if (!mAttachMenu)
04341 {
04342 mAttachMenu =
new QPopupMenu(
this);
04343
04344 mAttachMenu->insertItem(i18n(
"to view",
"View"),
this,
04345 SLOT(slotAttachView()));
04346 mAttachMenu->insertItem(i18n(
"Remove"),
this, SLOT(slotAttachRemove()));
04347 mSaveAsId = mAttachMenu->insertItem( SmallIcon(
"filesaveas"), i18n(
"Save As..."),
this,
04348 SLOT( slotAttachSave() ) );
04349 mPropertiesId = mAttachMenu->insertItem( i18n(
"Properties"),
this,
04350 SLOT( slotAttachProperties() ) );
04351 mAttachMenu->insertSeparator();
04352 mAttachMenu->insertItem(i18n(
"Add Attachment..."),
this, SLOT(slotAttachFile()));
04353 }
04354
04355
int selectedCount = 0;
04356
for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it ) {
04357
if ( (*it)->isSelected() ) {
04358 ++selectedCount;
04359 }
04360 }
04361
bool multiSelection = ( selectedCount > 1 );
04362 mAttachMenu->setItemEnabled( mSaveAsId, !multiSelection );
04363 mAttachMenu->setItemEnabled( mPropertiesId, !multiSelection );
04364
04365 mAttachMenu->popup(QCursor::pos());
04366 }
04367
04368
04369
int KMComposeWin::currentAttachmentNum()
04370 {
04371
int i = 0;
04372
for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i )
04373
if ( *it == mAtmListView->currentItem() )
04374
return i;
04375
return -1;
04376 }
04377
04378
04379
void KMComposeWin::slotAttachProperties()
04380 {
04381
int idx = currentAttachmentNum();
04382
04383
if (idx < 0)
return;
04384
04385 KMMessagePart* msgPart = mAtmList.at(idx);
04386 msgPart->setCharset(mCharset);
04387
04388
KMMsgPartDialogCompat dlg;
04389 dlg.
setMsgPart(msgPart);
04390 KMAtmListViewItem* listItem = (KMAtmListViewItem*)(mAtmItemList.at(idx));
04391
if( mSelectedCryptPlug && listItem ) {
04392 dlg.
setCanSign(
true );
04393 dlg.
setCanEncrypt(
true );
04394 dlg.
setSigned( listItem->isSign() );
04395 dlg.
setEncrypted( listItem->isEncrypt() );
04396 }
else {
04397 dlg.
setCanSign(
false );
04398 dlg.
setCanEncrypt(
false );
04399 }
04400
if (dlg.exec())
04401 {
04402 mAtmModified = TRUE;
04403
04404
if( listItem ) {
04405 msgPartToItem(msgPart, listItem);
04406
if( mSelectedCryptPlug ) {
04407 listItem->setSign( dlg.
isSigned() );
04408 listItem->setEncrypt( dlg.
isEncrypted() );
04409 }
04410 }
04411 }
04412
if (msgPart->typeStr().lower() !=
"text") msgPart->setCharset(QCString());
04413 }
04414
04415
04416
04417
void KMComposeWin::slotAttachView()
04418 {
04419
int i = 0;
04420
for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
04421
if ( (*it)->isSelected() ) {
04422 viewAttach( i );
04423 }
04424 }
04425 }
04426
04427
04428
04429
void KMComposeWin::viewAttach(
int index )
04430 {
04431 QString str, pname;
04432 KMMessagePart* msgPart;
04433 msgPart = mAtmList.at(index);
04434 pname = msgPart->name().stripWhiteSpace();
04435
if (pname.isEmpty()) pname=msgPart->contentDescription();
04436
if (pname.isEmpty()) pname=
"unnamed";
04437
04438 KTempFile* atmTempFile =
new KTempFile();
04439 mAtmTempList.append( atmTempFile );
04440 atmTempFile->setAutoDelete(
true );
04441 kByteArrayToFile(msgPart->bodyDecodedBinary(), atmTempFile->name(),
false,
false,
04442
false);
04443 KMReaderMainWin *win =
new KMReaderMainWin(msgPart,
false,
04444 atmTempFile->name(), pname, KMMsgBase::codecForName(mCharset) );
04445 win->show();
04446 }
04447
04448
04449
04450
void KMComposeWin::slotAttachSave()
04451 {
04452 KMMessagePart* msgPart;
04453 QString fileName, pname;
04454
int idx = currentAttachmentNum();
04455
04456
if (idx < 0)
return;
04457
04458 msgPart = mAtmList.at(idx);
04459 pname = msgPart->name();
04460
if (pname.isEmpty()) pname=
"unnamed";
04461
04462 KURL url = KFileDialog::getSaveURL(QString::null, QString::null, 0, i18n(
"Save Attachment As"));
04463
04464
if( url.isEmpty() )
04465
return;
04466
04467 kmkernel->byteArrayToRemoteFile(msgPart->bodyDecodedBinary(), url);
04468 }
04469
04470
04471
04472
void KMComposeWin::slotAttachRemove()
04473 {
04474
bool attachmentRemoved =
false;
04475
int i = 0;
04476
for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ) {
04477
if ( (*it)->isSelected() ) {
04478 removeAttach( i );
04479 attachmentRemoved =
true;
04480 }
04481
else {
04482 ++it;
04483 ++i;
04484 }
04485 }
04486
04487
if ( attachmentRemoved ) {
04488 mEditor->setModified(
true );
04489 slotUpdateAttachActions();
04490 }
04491 }
04492
04493
04494
void KMComposeWin::slotFind()
04495 {
04496 mEditor->search();
04497 }
04498
04499
04500
04501
void KMComposeWin::slotReplace()
04502 {
04503 mEditor->replace();
04504 }
04505
04506
04507
void KMComposeWin::slotUpdateFont()
04508 {
04509 mEditor->setFont( mFixedFontAction && (mFixedFontAction->isChecked())
04510 ? mFixedFont : mBodyFont );
04511 }
04512
04513 QString KMComposeWin::quotePrefixName()
const
04514
{
04515
if ( !msg() )
04516
return QString::null;
04517
04518 KConfig *config=KMKernel::config();
04519 KConfigGroupSaver saver(config,
"General");
04520
04521
int languageNr = config->readNumEntry(
"reply-current-language",0);
04522 config->setGroup( QString(
"KMMessage #%1").arg(languageNr) );
04523
04524 QString quotePrefix = config->readEntry(
"indent-prefix",
">%_");
04525 quotePrefix = msg()->formatString(quotePrefix);
04526
return quotePrefix;
04527 }
04528
04529
void KMComposeWin::slotPasteAsQuotation()
04530 {
04531
if( mEditor->hasFocus() && msg() )
04532 {
04533 QString quotePrefix = quotePrefixName();
04534 QString s = QApplication::clipboard()->text();
04535
if (!s.isEmpty()) {
04536
for (
int i=0; (uint)i<s.length(); i++) {
04537
if ( s[i] <
' ' && s[i] !=
'\n' && s[i] !=
'\t' )
04538 s[i] =
' ';
04539 }
04540 s.prepend(quotePrefix);
04541 s.replace(
"\n",
"\n"+quotePrefix);
04542 mEditor->insert(s);
04543 }
04544 }
04545 }
04546
04547
04548
void KMComposeWin::slotAddQuotes()
04549 {
04550
if( mEditor->hasFocus() && msg() )
04551 {
04552
if ( mEditor->hasMarkedText()) {
04553 QString s = mEditor->markedText();
04554 QString quotePrefix = quotePrefixName();
04555 s.prepend(quotePrefix);
04556 s.replace(
"\n",
"\n"+quotePrefix);
04557 mEditor->insert(s);
04558 }
else {
04559
int l = mEditor->currentLine();
04560
int c = mEditor->currentColumn();
04561 QString s = mEditor->textLine(l);
04562 s.prepend(
"> ");
04563 mEditor->insertLine(s,l);
04564 mEditor->removeLine(l+1);
04565 mEditor->setCursorPosition(l,c+2);
04566 }
04567 }
04568 }
04569
04570
04571
void KMComposeWin::slotRemoveQuotes()
04572 {
04573
if( mEditor->hasFocus() && msg() )
04574 {
04575 QString quotePrefix = quotePrefixName();
04576
if (mEditor->hasMarkedText()) {
04577 QString s = mEditor->markedText();
04578 QString quotePrefix = quotePrefixName();
04579
if (s.left(2) == quotePrefix )
04580 s.remove(0,2);
04581 s.replace(
"\n"+quotePrefix,
"\n");
04582 mEditor->insert(s);
04583 }
else {
04584
int l = mEditor->currentLine();
04585
int c = mEditor->currentColumn();
04586 QString s = mEditor->textLine(l);
04587
if (s.left(2) == quotePrefix) {
04588 s.remove(0,2);
04589 mEditor->insertLine(s,l);
04590 mEditor->removeLine(l+1);
04591 mEditor->setCursorPosition(l,c-2);
04592 }
04593 }
04594 }
04595 }
04596
04597
04598
04599
void KMComposeWin::slotUndo()
04600 {
04601 QWidget* fw = focusWidget();
04602
if (!fw)
return;
04603
04604
if (fw->inherits(
"KEdit"))
04605 ((QMultiLineEdit*)fw)->undo();
04606
else if (fw->inherits(
"QLineEdit"))
04607 ((QLineEdit*)fw)->undo();
04608 }
04609
04610
void KMComposeWin::slotRedo()
04611 {
04612 QWidget* fw = focusWidget();
04613
if (!fw)
return;
04614
04615
if (fw->inherits(
"KEdit"))
04616 ((QMultiLineEdit*)fw)->redo();
04617
else if (fw->inherits(
"QLineEdit"))
04618 ((QLineEdit*)fw)->redo();
04619 }
04620
04621
04622
void KMComposeWin::slotCut()
04623 {
04624 QWidget* fw = focusWidget();
04625
if (!fw)
return;
04626
04627
if (fw->inherits(
"KEdit"))
04628 ((QMultiLineEdit*)fw)->cut();
04629
else if (fw->inherits(
"QLineEdit"))
04630 ((QLineEdit*)fw)->cut();
04631
else kdDebug(5006) <<
"wrong focus widget" << endl;
04632 }
04633
04634
04635
04636
void KMComposeWin::slotCopy()
04637 {
04638 QWidget* fw = focusWidget();
04639
if (!fw)
return;
04640
04641
#ifdef KeyPress
04642
#undef KeyPress
04643
#endif
04644
04645 QKeyEvent k(QEvent::KeyPress, Key_C , 0 , ControlButton);
04646 kapp->notify(fw, &k);
04647 }
04648
04649
04650
04651
void KMComposeWin::slotPaste()
04652 {
04653 QWidget* fw = focusWidget();
04654
if (!fw)
return;
04655
04656
#ifdef KeyPress
04657
#undef KeyPress
04658
#endif
04659
04660 QKeyEvent k(QEvent::KeyPress, Key_V , 0 , ControlButton);
04661 kapp->notify(fw, &k);
04662 }
04663
04664
04665
04666
void KMComposeWin::slotMarkAll()
04667 {
04668 QWidget* fw = focusWidget();
04669
if (!fw)
return;
04670
04671
if (fw->inherits(
"QLineEdit"))
04672 ((QLineEdit*)fw)->selectAll();
04673
else if (fw->inherits(
"QMultiLineEdit"))
04674 ((QMultiLineEdit*)fw)->selectAll();
04675 }
04676
04677
04678
04679
void KMComposeWin::slotClose()
04680 {
04681 close(FALSE);
04682 }
04683
04684
04685
04686
void KMComposeWin::slotNewComposer()
04687 {
04688 KMComposeWin* win;
04689 KMMessage* msg =
new KMMessage;
04690
04691 msg->initHeader();
04692 win =
new KMComposeWin(msg);
04693 win->show();
04694 }
04695
04696
04697
04698
void KMComposeWin::slotNewMailReader()
04699 {
04700 KMMainWin *kmmwin =
new KMMainWin(0);
04701 kmmwin->show();
04702
04703 }
04704
04705
04706
04707
void KMComposeWin::slotUpdWinTitle(
const QString& text)
04708 {
04709
if (text.isEmpty())
04710 setCaption(
"("+i18n(
"unnamed")+
")");
04711
else setCaption(text);
04712 }
04713
04714
04715
04716
void KMComposeWin::slotEncryptToggled(
bool on)
04717 {
04718 setEncryption( on,
true );
04719 }
04720
04721
04722
04723
void KMComposeWin::setEncryption(
bool encrypt,
bool setByUser )
04724 {
04725
if ( !mEncryptAction->isEnabled() )
04726 encrypt =
false;
04727
04728
04729
04730
if ( encrypt && Kpgp::Module::getKpgp()->encryptToSelf()
04731 && !mLastIdentityHasOpenPgpKey
04732
04733 && ( !mSelectedCryptPlug || mSelectedCryptPlug->protocol() ==
"openpgp" ) ) {
04734
if ( setByUser ) {
04735 KMessageBox::sorry(
this,
04736 i18n(
"<qt><p>In order to be able to encrypt "
04737
"this message you first have to "
04738
"define the OpenPGP key, which should be "
04739
"used to encrypt the message to "
04740
"yourself.</p>"
04741
"<p>You can define the OpenPGP key, "
04742
"which should be used with the current "
04743
"identity, in the identity configuration.</p>"
04744
"</qt>"),
04745 i18n(
"Undefined Encryption Key") );
04746 }
04747 encrypt =
false;
04748 }
04749
04750
04751 mEncryptAction->setChecked( encrypt );
04752
04753
04754
if ( encrypt )
04755 mEncryptAction->setIcon(
"encrypted");
04756
else
04757 mEncryptAction->setIcon(
"decrypted");
04758
04759
04760
if ( mSelectedCryptPlug ) {
04761
for ( KMAtmListViewItem* entry =
04762 static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
04763 entry;
04764 entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
04765 entry->setEncrypt( encrypt );
04766 }
04767 }
04768
04769
04770
04771
void KMComposeWin::slotSignToggled(
bool on)
04772 {
04773 setSigning( on,
true );
04774 }
04775
04776
04777
04778
void KMComposeWin::setSigning(
bool sign,
bool setByUser )
04779 {
04780
if ( !mSignAction->isEnabled() )
04781 sign =
false;
04782
04783
04784
if ( sign && !mLastIdentityHasOpenPgpKey
04785
04786 && ( !mSelectedCryptPlug || mSelectedCryptPlug->protocol() ==
"openpgp" ) ) {
04787
if ( setByUser ) {
04788 KMessageBox::sorry(
this,
04789 i18n(
"<qt><p>In order to be able to sign "
04790
"this message you first have to "
04791
"define the OpenPGP key which should be "
04792
"used for this.</p>"
04793
"<p>You can define the OpenPGP key "
04794
"which should be used with the current "
04795
"identity in the identity configuration.</p>"
04796
"</qt>"),
04797 i18n(
"Undefined Signing Key") );
04798 }
04799 sign =
false;
04800 }
04801
04802
04803 mSignAction->setChecked( sign );
04804
04805
04806
if ( mSelectedCryptPlug ) {
04807
for ( KMAtmListViewItem* entry =
04808 static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
04809 entry;
04810 entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
04811 entry->setSign( sign );
04812 }
04813 }
04814
04815
04816
04817
void KMComposeWin::slotWordWrapToggled(
bool on)
04818 {
04819
if (on)
04820 {
04821 mEditor->setWordWrap( QMultiLineEdit::FixedColumnWidth );
04822 mEditor->setWrapColumnOrWidth(mLineBreak);
04823 }
04824
else
04825 {
04826 mEditor->setWordWrap( QMultiLineEdit::NoWrap );
04827 }
04828 }
04829
04830
04831
04832
void KMComposeWin::slotPrint()
04833 {
04834
bool bMessageWasModified = ( mEditor->isModified() || mEdtFrom->edited() ||
04835 mEdtReplyTo->edited() || mEdtTo->edited() ||
04836 mEdtCc->edited() || mEdtBcc->edited() ||
04837 mEdtSubject->edited() || mAtmModified ||
04838 ( mTransport->lineEdit() &&
04839 mTransport->lineEdit()->edited() ) );
04840 applyChanges(
true );
04841 KMCommand *command =
new KMPrintCommand(
this, mMsg );
04842 command->start();
04843 mEditor->setModified( bMessageWasModified );
04844 }
04845
04846
04847
04848
bool KMComposeWin::doSend(
int aSendNow,
bool saveInDrafts)
04849 {
04850
if (!saveInDrafts)
04851 {
04852
if (to().isEmpty())
04853 {
04854 mEdtTo->setFocus();
04855 KMessageBox::information(
this,
04856 i18n(
"You must specify at least one "
04857
"receiver in the To: field.") );
04858
return false;
04859 }
04860
04861
if (subject().isEmpty())
04862 {
04863 mEdtSubject->setFocus();
04864
int rc =
04865 KMessageBox::questionYesNo(
this,
04866 i18n(
"You did not specify a subject. "
04867
"Send message anyway?"),
04868 i18n(
"No Subject Specified"),
04869 i18n(
"&Yes, Send as Is"),
04870 i18n(
"&No, Let Me Specify the Subject"),
04871
"no_subject_specified" );
04872
if( rc == KMessageBox::No )
04873 {
04874
return false;
04875 }
04876 }
04877
04878
if ( userForgotAttachment() )
04879
return false;
04880 }
04881
04882
KCursorSaver busy(KBusyPtr::busy());
04883 mMsg->setDateToday();
04884
04885
04886
04887
04888
04889
04890 QString hf = mMsg->headerField(
"X-KMail-Transport");
04891
if ((mTransport->currentText() != mTransport->text(0)) ||
04892 (!hf.isEmpty() && (hf != mTransport->text(0))))
04893 mMsg->setHeaderField(
"X-KMail-Transport", mTransport->currentText());
04894
04895 mDisableBreaking = saveInDrafts;
04896
04897 mBccMsgList.clear();
04898
bool sentOk = applyChanges();
04899
if( sentOk ) {
04900
if (!mAutoDeleteMsg) mEditor->setModified(FALSE);
04901 mEdtFrom->setEdited(FALSE);
04902 mEdtReplyTo->setEdited(FALSE);
04903 mEdtTo->setEdited(FALSE);
04904 mEdtCc->setEdited(FALSE);
04905 mEdtBcc->setEdited(FALSE);
04906 mEdtSubject->setEdited(FALSE);
04907
if (mTransport->lineEdit())
04908 mTransport->lineEdit()->setEdited(FALSE);
04909 mAtmModified = FALSE;
04910
04911
04912 mMsg->cleanupHeader();
04913 }
04914
04915 mDisableBreaking =
false;
04916
04917
if (!sentOk)
04918
return false;
04919
04920
04921 mMsg->setComplete(
true );
04922
04923
if (saveInDrafts)
04924 {
04925
KMFolder* draftsFolder = 0, *imapDraftsFolder = 0;
04926
04927
if ( !mMsg->drafts().isEmpty() )
04928 {
04929 draftsFolder = kmkernel->folderMgr()->findIdString( mMsg->drafts() );
04930
if ( draftsFolder == 0 )
04931
04932
04933 draftsFolder = kmkernel->imapFolderMgr()->findIdString( mMsg->drafts() );
04934
if ( draftsFolder == 0 )
04935 imapDraftsFolder = kmkernel->imapFolderMgr()->findIdString( mMsg->drafts() );
04936
if ( !draftsFolder && !imapDraftsFolder )
04937 {
04938
const KMIdentity &
id = kmkernel->identityManager()
04939 ->identityForUoidOrDefault( mMsg->headerField(
"X-KMail-Identity" ).stripWhiteSpace().toUInt() );
04940 KMessageBox::information(0, i18n(
"The custom drafts folder for identity "
04941
"\"%1\" doesn't exist (anymore). "
04942
"Therefore the default drafts folder "
04943
"will be used.")
04944 .arg(
id.identityName() ) );
04945 }
04946 }
04947
if (imapDraftsFolder && imapDraftsFolder->
noContent())
04948 imapDraftsFolder = 0;
04949
04950
if ( draftsFolder == 0 ) {
04951 draftsFolder = kmkernel->draftsFolder();
04952 }
else {
04953 draftsFolder->
open();
04954 }
04955 kdDebug(5006) <<
"saveindrafts: drafts=" << draftsFolder->name() << endl;
04956
if (imapDraftsFolder)
04957 kdDebug(5006) <<
"saveindrafts: imapdrafts="
04958 << imapDraftsFolder->name() << endl;
04959
04960 sentOk = !(draftsFolder->
addMsg(mMsg));
04961
if (imapDraftsFolder)
04962 {
04963
04964 imapDraftsFolder->
moveMsg(mMsg);
04965 (static_cast<KMFolderImap*>(imapDraftsFolder))->getFolder();
04966 }
04967
04968 }
else {
04969 mMsg->setTo( KMMessage::expandAliases( to() ));
04970 mMsg->setCc( KMMessage::expandAliases( cc() ));
04971
if( !mBcc.isEmpty() )
04972 mMsg->setBcc( KMMessage::expandAliases( mBcc ));
04973 QString recips = mMsg->headerField(
"X-KMail-Recipients" );
04974
if( !recips.isEmpty() ) {
04975 mMsg->setHeaderField(
"X-KMail-Recipients", KMMessage::expandAliases( recips ) );
04976 }
04977 mMsg->cleanupHeader();
04978 sentOk = kmkernel->msgSender()->send(mMsg, aSendNow);
04979 KMMessage* msg;
04980
for( msg = mBccMsgList.first(); msg; msg = mBccMsgList.next() ) {
04981 msg->setTo( KMMessage::expandAliases( to() ));
04982 msg->setCc( KMMessage::expandAliases( cc() ));
04983 msg->setBcc( KMMessage::expandAliases( bcc() ));
04984 QString recips = msg->headerField(
"X-KMail-Recipients" );
04985
if( !recips.isEmpty() ) {
04986 msg->setHeaderField(
"X-KMail-Recipients", KMMessage::expandAliases( recips ) );
04987 }
04988 msg->cleanupHeader();
04989 sentOk &= kmkernel->msgSender()->send(msg, aSendNow);
04990 }
04991 }
04992
04993
if (!sentOk)
04994
return false;
04995
04996
if (saveInDrafts || !aSendNow)
04997 emit messageQueuedOrDrafted();
04998
04999 RecentAddresses::self(KMKernel::config())->add( bcc() );
05000 RecentAddresses::self(KMKernel::config())->add( cc() );
05001 RecentAddresses::self(KMKernel::config())->add( to() );
05002
05003 mAutoDeleteMsg = FALSE;
05004 mFolder = 0;
05005 close();
05006
return true;
05007 }
05008
05009
05010
05011
05012
void KMComposeWin::slotSendLater()
05013 {
05014
if ( mEditor->checkExternalEditorFinished() )
05015 doSend(
false );
05016 }
05017
05018
05019
05020
bool KMComposeWin::slotSaveDraft() {
05021
return mEditor->checkExternalEditorFinished() && doSend(
false,
true );
05022 }
05023
05024
05025
05026
void KMComposeWin::slotSendNow() {
05027
if ( !mEditor->checkExternalEditorFinished() )
05028
return;
05029
if (mConfirmSend) {
05030
switch(KMessageBox::warningYesNoCancel(mMainWidget,
05031 i18n(
"About to send email..."),
05032 i18n(
"Send Confirmation"),
05033 i18n(
"Send &Now"),
05034 i18n(
"Send &Later"))) {
05035
case KMessageBox::Yes:
05036 doSend(TRUE);
05037
break;
05038
case KMessageBox::No:
05039 doSend(FALSE);
05040
break;
05041
case KMessageBox::Cancel:
05042
break;
05043
default:
05044 ;
05045 }
05046
return;
05047 }
05048
05049 doSend(TRUE);
05050 }
05051
05052
05053
05054
void KMComposeWin::slotAppendSignature()
05055 {
05056
bool mod = mEditor->isModified();
05057
05058
const KMIdentity & ident =
05059 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
05060 mOldSigText = ident.
signatureText();
05061
if( !mOldSigText.isEmpty() )
05062 {
05063 mEditor->sync();
05064 mEditor->append(mOldSigText);
05065 mEditor->update();
05066 mEditor->setModified(mod);
05067 mEditor->setContentsPos( 0, 0 );
05068 }
05069 kmkernel->dumpDeadLetters();
05070 }
05071
05072
05073
05074
void KMComposeWin::slotHelp()
05075 {
05076 kapp->invokeHelp();
05077 }
05078
05079
05080
void KMComposeWin::slotCleanSpace()
05081 {
05082 mEditor->cleanWhiteSpace();
05083 }
05084
05085
05086
05087
void KMComposeWin::slotSpellcheck()
05088 {
05089
if (mSpellCheckInProgress)
return;
05090
05091 mSpellCheckInProgress=TRUE;
05092
05093
05094
05095
05096
05097 mEditor->spellcheck();
05098 }
05099
05100
05101
05102
void KMComposeWin::slotSpellcheckDone(
int result)
05103 {
05104 kdDebug(5006) <<
"spell check complete: result = " << result << endl;
05105 mSpellCheckInProgress=FALSE;
05106
05107
switch( result )
05108 {
05109
case KS_CANCEL:
05110 statusBar()->changeItem(i18n(
" Spell check canceled."),0);
05111
break;
05112
case KS_STOP:
05113 statusBar()->changeItem(i18n(
" Spell check stopped."),0);
05114
break;
05115
default:
05116 statusBar()->changeItem(i18n(
" Spell check complete."),0);
05117
break;
05118 }
05119 QTimer::singleShot( 2000,
this, SLOT(slotSpellcheckDoneClearStatus()) );
05120 }
05121
05122
void KMComposeWin::slotSpellcheckDoneClearStatus()
05123 {
05124 statusBar()->changeItem(
"", 0);
05125 }
05126
05127
05128
05129
void KMComposeWin::focusNextPrevEdit(
const QWidget* aCur,
bool aNext)
05130 {
05131 QWidget* cur;
05132
05133
if (!aCur)
05134 {
05135 cur=mEdtList.last();
05136 }
05137
else
05138 {
05139
for (cur=mEdtList.first(); aCur!=cur && cur; cur=mEdtList.next())
05140 ;
05141
if (!cur)
return;
05142
if (aNext) cur = mEdtList.next();
05143
else cur = mEdtList.prev();
05144 }
05145
if (cur) cur->setFocus();
05146
else if (aNext) mEditor->setFocus();
05147 }
05148
05149
05150
void KMComposeWin::slotIdentityChanged(uint uoid)
05151 {
05152
const KMIdentity & ident =
05153 kmkernel->identityManager()->identityForUoid( uoid );
05154
if ( ident.
isNull() )
return;
05155
05156
if(!ident.
fullEmailAddr().isNull())
05157 mEdtFrom->setText(ident.
fullEmailAddr());
05158 mEdtReplyTo->setText(ident.
replyToAddr());
05159
05160
05161
if( !mEdtBcc->edited() || !ident.
bcc().isEmpty() )
05162 mEdtBcc->setText(ident.
bcc());
05163
05164
if (! ident.
bcc().isEmpty()) {
05165 mShowHeaders |= HDR_BCC;
05166 }
05167
if (ident.
organization().isEmpty())
05168 mMsg->removeHeaderField(
"Organization");
05169
else
05170 mMsg->setHeaderField(
"Organization", ident.
organization());
05171
05172
if (!mBtnTransport->isChecked()) {
05173 QString transp = ident.
transport();
05174
if (transp.isEmpty())
05175 {
05176 mMsg->removeHeaderField(
"X-KMail-Transport");
05177 transp = mTransport->text(0);
05178 }
05179
else
05180 mMsg->setHeaderField(
"X-KMail-Transport", transp);
05181
bool found =
false;
05182
int i;
05183
for (i = 0; i < mTransport->count(); i++) {
05184
if (mTransport->text(i) == transp) {
05185 found =
true;
05186 mTransport->setCurrentItem(i);
05187
break;
05188 }
05189 }
05190
if (found ==
false) {
05191
if (i == mTransport->maxCount()) mTransport->setMaxCount(i + 1);
05192 mTransport->insertItem(transp,i);
05193 mTransport->setCurrentItem(i);
05194 }
05195 }
05196
05197 mDictionaryCombo->setCurrentByDictionary( ident.
dictionary() );
05198
05199
if ( !mBtnFcc->isChecked() )
05200 {
05201
if ( ident.
fcc().isEmpty() )
05202 mFcc->setFolder( kmkernel->sentFolder() );
05203
else
05204 setFcc( ident.
fcc() );
05205 }
05206
05207 QString edtText = mEditor->text();
05208
bool appendNewSig =
true;
05209
05210
if( !mOldSigText.isEmpty() )
05211 {
05212
if( edtText.endsWith( mOldSigText ) )
05213 edtText.truncate( edtText.length() - mOldSigText.length() );
05214
else
05215 appendNewSig =
false;
05216 }
05217
05218 mOldSigText = ident.
signatureText();
05219
if( appendNewSig )
05220 {
05221
if( !mOldSigText.isEmpty() && mAutoSign )
05222 edtText.append( mOldSigText );
05223 mEditor->setText( edtText );
05224 }
05225
05226
05227
05228
bool bNewIdentityHasOpenPgpKey = !ident.
pgpIdentity().isEmpty();
05229
if( !mSelectedCryptPlug && !bNewIdentityHasOpenPgpKey )
05230 {
05231 mAttachMPK->setEnabled(
false);
05232
if( mLastIdentityHasOpenPgpKey )
05233 {
05234 mLastEncryptActionState = mEncryptAction->isChecked();
05235 setEncryption(
false );
05236 mLastSignActionState = mSignAction->isChecked();
05237 setSigning(
false );
05238 }
05239 }
05240
else
05241 {
05242 mAttachMPK->setEnabled(
true);
05243
if( !mLastIdentityHasOpenPgpKey )
05244 {
05245 setEncryption( mLastEncryptActionState );
05246 setSigning( mLastSignActionState );
05247 }
05248 }
05249 mLastIdentityHasOpenPgpKey = bNewIdentityHasOpenPgpKey;
05250
05251 mEditor->setModified(TRUE);
05252 mId = uoid;
05253
05254
05255 rethinkFields(
false );
05256 }
05257
05258
05259
void KMComposeWin::slotSpellcheckConfig()
05260 {
05261 KWin kwin;
05262 QTabDialog qtd (
this,
"tabdialog",
true);
05263 KSpellConfig mKSpellConfig (&qtd);
05264
05265 qtd.addTab (&mKSpellConfig, i18n(
"Spellchecker"));
05266 qtd.setCancelButton ();
05267
05268 kwin.setIcons (qtd.winId(), kapp->icon(), kapp->miniIcon());
05269 qtd.setCancelButton(KStdGuiItem::cancel().text());
05270 qtd.setOkButton(KStdGuiItem::ok().text());
05271
05272
if (qtd.exec())
05273 mKSpellConfig.writeGlobalSettings();
05274 }
05275
05276
05277
void KMComposeWin::slotStatusMessage(
const QString &message)
05278 {
05279 statusBar()->changeItem( message, 0 );
05280 }
05281
05282
void KMComposeWin::slotEditToolbars()
05283 {
05284 saveMainWindowSettings(KMKernel::config(),
"Composer");
05285 KEditToolbar dlg(guiFactory(),
this);
05286
05287 connect( &dlg, SIGNAL(newToolbarConfig()),
05288 SLOT(slotUpdateToolbars()) );
05289
05290 dlg.exec();
05291 }
05292
05293
void KMComposeWin::slotUpdateToolbars()
05294 {
05295 createGUI(
"kmcomposerui.rc");
05296 applyMainWindowSettings(KMKernel::config(),
"Composer");
05297 }
05298
05299
void KMComposeWin::slotEditKeys()
05300 {
05301 KKeyDialog::configure( actionCollection(),
05302
false
05303 );
05304 }
05305
05306
void KMComposeWin::setReplyFocus(
bool hasMessage )
05307 {
05308 mEditor->setFocus();
05309
if ( hasMessage )
05310 mEditor->setCursorPosition( 1, 0 );
05311 }
05312
05313
void KMComposeWin::setFocusToSubject()
05314 {
05315 mEdtSubject->setFocus();
05316 }
05317
05318
void KMComposeWin::slotCompletionModeChanged( KGlobalSettings::Completion mode)
05319 {
05320 KConfig *config = KMKernel::config();
05321 KConfigGroupSaver cs( config,
"Composer" );
05322 config->writeEntry(
"Completion Mode", (
int) mode );
05323 config->sync();
05324
05325
05326 mEdtFrom->setCompletionMode( mode );
05327 mEdtReplyTo->setCompletionMode( mode );
05328 mEdtTo->setCompletionMode( mode );
05329 mEdtCc->setCompletionMode( mode );
05330 mEdtBcc->setCompletionMode( mode );
05331 }
05332
05333
void KMComposeWin::slotConfigChanged()
05334 {
05335 readConfig();
05336 }
05337
05338
05339
05340
05341
05342
void KMComposeWin::slotFolderRemoved(
KMFolder* folder)
05343 {
05344
if ( (mFolder) && (folder->
idString() == mFolder->idString()) )
05345 {
05346 mFolder = kmkernel->draftsFolder();
05347 kdDebug(5006) <<
"restoring drafts to " << mFolder->idString() << endl;
05348 }
05349
if (mMsg) mMsg->setParent(0);
05350 }
05351
05352
05353
05354
void KMComposeWin::slotSetAlwaysSend(
bool bAlways )
05355 {
05356 mAlwaysSend = bAlways;
05357 }
05358
05359
void KMEdit::contentsDragEnterEvent(QDragEnterEvent *e)
05360 {
05361
if (e->provides(MailListDrag::format()))
05362 e->accept(
true);
05363
else
05364
return KEdit::dragEnterEvent(e);
05365 }
05366
05367
void KMEdit::contentsDragMoveEvent(QDragMoveEvent *e)
05368 {
05369
if (e->provides(MailListDrag::format()))
05370 e->accept();
05371
else
05372
return KEdit::dragMoveEvent(e);
05373 }
05374
05375
void KMEdit::keyPressEvent( QKeyEvent* e )
05376 {
05377
if( e->key() == Key_Return ) {
05378
int line, col;
05379 getCursorPosition( &line, &col );
05380 QString lineText = text( line );
05381
05382 lineText.truncate( lineText.length() - 1 );
05383
05384
05385
if( ( col > 0 ) && ( col < int( lineText.length() ) ) ) {
05386
bool isQuotedLine =
false;
05387 uint bot = 0;
05388
while( bot < lineText.length() ) {
05389
if( ( lineText[bot] ==
'>' ) || ( lineText[bot] ==
'|' ) ) {
05390 isQuotedLine =
true;
05391 ++bot;
05392 }
05393
else if( lineText[bot].isSpace() ) {
05394 ++bot;
05395 }
05396
else {
05397
break;
05398 }
05399 }
05400
05401 KEdit::keyPressEvent( e );
05402
05403
05404
05405
05406
if( isQuotedLine
05407 && ( bot != lineText.length() )
05408 && ( col >= int( bot ) ) ) {
05409 QString newLine = text( line + 1 );
05410
05411
05412
unsigned int leadingWhiteSpaceCount = 0;
05413
while( ( leadingWhiteSpaceCount < newLine.length() )
05414 && newLine[leadingWhiteSpaceCount].isSpace() ) {
05415 ++leadingWhiteSpaceCount;
05416 }
05417 newLine = newLine.replace( 0, leadingWhiteSpaceCount,
05418 lineText.left( bot ) );
05419 removeParagraph( line + 1 );
05420 insertParagraph( newLine, line + 1 );
05421
05422
05423
05424 setCursorPosition( line + 1 , 0 );
05425 }
05426 }
05427
else
05428 KEdit::keyPressEvent( e );
05429 }
05430
else
05431 KEdit::keyPressEvent( e );
05432 }
05433
05434
void KMEdit::contentsDropEvent(QDropEvent *e)
05435 {
05436
if (e->provides(MailListDrag::format())) {
05437
05438 QByteArray serNums;
05439 MailListDrag::decode( e, serNums );
05440 QBuffer serNumBuffer(serNums);
05441 serNumBuffer.open(IO_ReadOnly);
05442 QDataStream serNumStream(&serNumBuffer);
05443
unsigned long serNum;
05444
KMFolder *folder = 0;
05445
int idx;
05446 QPtrList<KMMsgBase> messageList;
05447
while (!serNumStream.atEnd()) {
05448 KMMsgBase *msgBase = 0;
05449 serNumStream >> serNum;
05450 kmkernel->msgDict()->getLocation(serNum, &folder, &idx);
05451
if (folder)
05452 msgBase = folder->
getMsgBase(idx);
05453
if (msgBase)
05454 messageList.append( msgBase );
05455 }
05456 serNumBuffer.close();
05457 uint identity = folder ? folder->
identity() : 0;
05458 KMCommand *command =
05459
new KMForwardAttachedCommand(mComposer, messageList,
05460 identity, mComposer);
05461 command->start();
05462 }
05463
else if( KURLDrag::canDecode( e ) ) {
05464 KURL::List urlList;
05465
if( KURLDrag::decode( e, urlList ) ) {
05466
for( KURL::List::Iterator it = urlList.begin();
05467 it != urlList.end(); ++it ) {
05468 mComposer->addAttach( *it );
05469 }
05470 }
05471 }
05472
else {
05473
return KEdit::dropEvent(e);
05474 }
05475 }
05476
05477
05478
05479
05480
05481
05482
05483 KMAtmListViewItem::KMAtmListViewItem(QListView *parent) :
05484 QObject(), QListViewItem( parent )
05485 {
05486
05487 mCBSignEnabled =
false;
05488 mCBEncryptEnabled =
false;
05489
05490 mListview = parent;
05491 mCBEncrypt =
new QCheckBox(mListview->viewport());
05492 mCBSign =
new QCheckBox(mListview->viewport());
05493
05494 mCBEncrypt->hide();
05495 mCBSign->hide();
05496 }
05497
05498 KMAtmListViewItem::~KMAtmListViewItem()
05499 {
05500 }
05501
05502
void KMAtmListViewItem::paintCell( QPainter * p,
const QColorGroup & cg,
05503
int column,
int width,
int align )
05504 {
05505
05506
05507 QListViewItem::paintCell( p, cg, column, width, align );
05508
if( 4 == column || 5 == column ) {
05509 QRect r = mListview->itemRect(
this );
05510
if ( !r.size().isValid() ) {
05511 mListview->ensureItemVisible(
this );
05512 mListview->repaintContents( FALSE );
05513 r = mListview->itemRect(
this );
05514 }
05515
int colWidth = mListview->header()->sectionSize( column );
05516 r.setX( mListview->header()->sectionPos( column )
05517 + colWidth / 2
05518 - r.height() / 2
05519 - 1 );
05520 r.setY( r.y() + 1 );
05521 r.setWidth( r.height() - 2 );
05522 r.setHeight( r.height() - 2 );
05523 r = QRect( mListview->viewportToContents( r.topLeft() ), r.size() );
05524
05525 QCheckBox* cb = (4 == column) ? mCBEncrypt : mCBSign;
05526 cb->resize( r.size() );
05527 mListview->moveChild( cb, r.x(), r.y() );
05528
05529 QColor bg;
05530
if (isSelected())
05531 bg = cg.highlight();
05532
else
05533 bg = cg.base();
05534
05535
bool enabled = (4 == column) ? mCBEncryptEnabled : mCBSignEnabled;
05536 cb->setPaletteBackgroundColor(bg);
05537
if (enabled) cb->show();
05538 }
05539 }
05540
05541
void KMAtmListViewItem::enableCryptoCBs(
bool on)
05542 {
05543
if( mCBEncrypt ) {
05544 mCBEncryptEnabled = on;
05545 mCBEncrypt->setEnabled( on );
05546 }
05547
if( mCBSign ) {
05548 mCBSignEnabled = on;
05549 mCBSign->setEnabled( on );
05550 }
05551 }
05552
05553
void KMAtmListViewItem::setEncrypt(
bool on)
05554 {
05555
if( mCBEncrypt )
05556 mCBEncrypt->setChecked( on );
05557 }
05558
05559
bool KMAtmListViewItem::isEncrypt()
05560 {
05561
if( mCBEncrypt )
05562
return mCBEncrypt->isChecked();
05563
else
05564
return false;
05565 }
05566
05567
void KMAtmListViewItem::setSign(
bool on)
05568 {
05569
if( mCBSign )
05570 mCBSign->setChecked( on );
05571 }
05572
05573
bool KMAtmListViewItem::isSign()
05574 {
05575
if( mCBSign )
05576
return mCBSign->isChecked();
05577
else
05578
return false;
05579 }
05580
05581
05582
05583
05584
05585
05586
05587
05588
05589 KMLineEdit::KMLineEdit(KMComposeWin* composer,
bool useCompletion,
05590 QWidget *parent,
const char *name)
05591 : AddressLineEdit(parent,useCompletion,name), mComposer(composer)
05592 {
05593 }
05594
05595
05596
05597
void KMLineEdit::keyPressEvent(QKeyEvent *e)
05598 {
05599
05600
if ((e->key() == Key_Enter || e->key() == Key_Return) &&
05601 !completionBox()->isVisible())
05602 {
05603 mComposer->focusNextPrevEdit(
this,TRUE);
05604
return;
05605 }
05606
if (e->key() == Key_Up)
05607 {
05608 mComposer->focusNextPrevEdit(
this,FALSE);
05609
return;
05610 }
05611
if (e->key() == Key_Down)
05612 {
05613 mComposer->focusNextPrevEdit(
this,TRUE);
05614
return;
05615 }
05616
05617 AddressLineEdit::keyPressEvent(e);
05618 }
05619
05620
#if 0
05621
05622
void KMLineEdit::dropEvent(QDropEvent *e)
05623 {
05624 KURL::List uriList;
05625
if(KURLDrag::decode( e, uriList ))
05626 {
05627
for (KURL::List::ConstIterator it = uriList.begin(); it != uriList.end(); ++it)
05628 {
05629 smartInsert( (*it).url() );
05630 }
05631 }
05632
else {
05633
if (m_useCompletion)
05634 m_smartPaste =
true;
05635 QLineEdit::dropEvent(e);
05636 m_smartPaste =
false;
05637 }
05638 }
05639
05640
void KMLineEdit::smartInsert(
const QString &str,
int pos )
05641 {
05642 QString newText = str.stripWhiteSpace();
05643
if (newText.isEmpty())
05644
return;
05645
05646
05647 newText.replace( QRegExp(
"\r?\n"),
" " );
05648
05649 QString contents = text();
05650
05651
if( ( pos < 0 ) || ( pos > (
int) contents.length() ) )
05652 pos = contents.length();
05653
int start_sel = 0;
05654
int end_sel = 0;
05655
if (getSelection(&start_sel, &end_sel))
05656 {
05657
05658
if (pos > end_sel)
05659 pos -= (end_sel - start_sel);
05660
else if (pos > start_sel)
05661 pos = start_sel;
05662 contents = contents.left(start_sel) + contents.right(end_sel+1);
05663 }
05664
05665
int eot = contents.length();
05666
05667
while ((eot > 0) && contents[eot-1].isSpace()) eot--;
05668
if (eot == 0)
05669 {
05670 contents = QString::null;
05671 }
05672
else if (pos >= eot)
05673 {
05674
if (contents[eot-1] ==
',')
05675 eot--;
05676 contents.truncate(eot);
05677 contents +=
", ";
05678 pos = eot+2;
05679 }
05680
05681
if (newText.startsWith(
"mailto:"))
05682 {
05683 kdDebug(5006) <<
"Pasting '" << newText <<
"'" << endl;
05684 KURL u(newText);
05685 newText = u.path();
05686 kdDebug(5006) <<
"path of mailto URL: '" << newText <<
"'" << endl;
05687
05688
if (-1 != newText.find( QRegExp(
"=\\?.*\\?[bq]\\?.*\\?=") ) )
05689 newText = KMMsgBase::decodeRFC2047String( newText.latin1() );
05690 }
05691
else if (-1 != newText.find(
" at "))
05692 {
05693
05694 newText.replace(
" at ",
"@" );
05695 newText.replace(
" dot ",
"." );
05696 }
05697
else if (newText.contains(
"(at)"))
05698 {
05699 newText.replace( QRegExp(
"\\s*\\(at\\)\\s*"),
"@" );
05700 }
05701 contents = contents.left(pos)+newText+contents.mid(pos);
05702 setText(contents);
05703 setEdited(
true );
05704 setCursorPosition(pos+newText.length());
05705 }
05706
#endif
05707
05708
05709
void KMLineEdit::loadAddresses()
05710 {
05711 AddressLineEdit::loadAddresses();
05712
05713 QStringList recent = RecentAddresses::self(KMKernel::config())->addresses();
05714 QStringList::Iterator it = recent.begin();
05715
for ( ; it != recent.end(); ++it )
05716 addAddress( *it );
05717 }
05718
05719
05720 KMLineEditSpell::KMLineEditSpell(KMComposeWin* composer,
bool useCompletion,
05721 QWidget *parent,
const char *name)
05722 : KMLineEdit(composer,useCompletion,parent,name)
05723 {
05724 }
05725
05726
05727
void KMLineEditSpell::highLightWord(
unsigned int length,
unsigned int pos )
05728 {
05729 setSelection ( pos, length );
05730 }
05731
05732
void KMLineEditSpell::spellCheckDone(
const QString &s )
05733 {
05734
if( s != text() )
05735 setText( s );
05736 }
05737
05738
void KMLineEditSpell::spellCheckerMisspelling(
const QString &_text,
const QStringList&,
unsigned int pos)
05739 {
05740 highLightWord( _text.length(),pos );
05741 }
05742
05743
void KMLineEditSpell::spellCheckerCorrected(
const QString &old,
const QString &corr,
unsigned int pos)
05744 {
05745
if( old!= corr )
05746 {
05747 setSelection ( pos, old.length() );
05748 insert( corr );
05749 setSelection ( pos, corr.length() );
05750 }
05751 }
05752
05753
05754
05755
05756
05757
05758
05759 KMEdit::KMEdit(QWidget *parent, KMComposeWin* composer,
05760 KSpellConfig* autoSpellConfig,
05761
const char *name)
05762 : KEdit( parent, name ),
05763 mComposer( composer ),
05764 mKSpell( 0 ),
05765 mSpellingFilter( 0 ),
05766 mExtEditorTempFile( 0 ),
05767 mExtEditorTempFileWatcher( 0 ),
05768 mExtEditorProcess( 0 ),
05769 mUseExtEditor( false ),
05770 mWasModifiedBeforeSpellCheck( false ),
05771 mSpellChecker( 0 ),
05772 mSpellLineEdit( false )
05773 {
05774 installEventFilter(
this);
05775 KCursor::setAutoHideCursor(
this,
true,
true );
05776
05777 initializeAutoSpellChecking( autoSpellConfig );
05778 }
05779
05780
05781
void KMEdit::initializeAutoSpellChecking( KSpellConfig* autoSpellConfig )
05782 {
05783 KConfigGroup readerConfig( KMKernel::config(),
"Reader" );
05784 QColor defaultColor1( 0x00, 0x80, 0x00 );
05785 QColor defaultColor2( 0x00, 0x70, 0x00 );
05786 QColor defaultColor3( 0x00, 0x60, 0x00 );
05787 QColor defaultForeground( kapp->palette().active().text() );
05788 QColor col1 = readerConfig.readColorEntry(
"ForegroundColor", &defaultForeground );
05789 QColor col2 = readerConfig.readColorEntry(
"QuotedText3", &defaultColor3 );
05790 QColor col3 = readerConfig.readColorEntry(
"QuotedText2", &defaultColor2 );
05791 QColor col4 = readerConfig.readColorEntry(
"QuotedText1", &defaultColor1 );
05792 QColor c = Qt::red;
05793 QColor misspelled = readerConfig.readColorEntry(
"MisspelledColor", &c );
05794
05795 mSpellChecker =
new KDictSpellingHighlighter(
this,
true,
05796
false,
05797 misspelled,
05798
true,
05799 col1, col2, col3, col4,
05800 autoSpellConfig );
05801 connect( mSpellChecker, SIGNAL(activeChanged(
const QString &)),
05802 mComposer, SLOT(slotStatusMessage(
const QString &)));
05803 connect( mSpellChecker, SIGNAL(newSuggestions(
const QString&,
const QStringList&,
unsigned int)),
05804
this, SLOT(addSuggestion(
const QString&,
const QStringList&,
unsigned int)) );
05805 }
05806
05807
05808
void KMEdit::addSuggestion(
const QString& text,
const QStringList& lst,
unsigned int )
05809 {
05810 mReplacements[text] = lst;
05811 }
05812
05813
05814 KMEdit::~KMEdit()
05815 {
05816 removeEventFilter(
this);
05817
05818
delete mKSpell;
05819
delete mSpellChecker;
05820 }
05821
05822
05823
05824 QString KMEdit::brokenText()
05825 {
05826 QString temp, line;
05827
05828
int num_lines = numLines();
05829
for (
int i = 0; i < num_lines; ++i)
05830 {
05831
int lastLine = 0;
05832 line = textLine(i);
05833
for (
int j = 0; j < (
int)line.length(); ++j)
05834 {
05835
if (lineOfChar(i, j) > lastLine)
05836 {
05837 lastLine = lineOfChar(i, j);
05838 temp +=
'\n';
05839 }
05840 temp += line[j];
05841 }
05842
if (i + 1 < num_lines) temp +=
'\n';
05843 }
05844
05845
return temp;
05846 }
05847
05848
05849
bool KMEdit::eventFilter(QObject*o, QEvent* e)
05850 {
05851
if (o ==
this)
05852 KCursor::autoHideEventFilter(o, e);
05853
05854
if (e->type() == QEvent::KeyPress)
05855 {
05856 QKeyEvent *k = (QKeyEvent*)e;
05857
05858
if (mUseExtEditor) {
05859
if (k->key() == Key_Up)
05860 {
05861 mComposer->focusNextPrevEdit(0,
false);
05862
return TRUE;
05863 }
05864
05865
05866
if ( (k->key() == Key_Shift) || (k->key() == Key_Control) ||
05867 (k->key() == Key_Meta) || (k->key() == Key_Alt) )
05868
return true;
05869
if (mExtEditorTempFile)
return TRUE;
05870 QString sysLine = mExtEditor;
05871 mExtEditorTempFile =
new KTempFile();
05872
05873 mExtEditorTempFile->setAutoDelete(
true);
05874
05875 (*mExtEditorTempFile->textStream()) << text();
05876
05877 mExtEditorTempFile->close();
05878
05879 sysLine.replace(
"%f", mExtEditorTempFile->name() );
05880 mExtEditorProcess =
new KProcess();
05881 sysLine +=
" ";
05882
while (!sysLine.isEmpty())
05883 {
05884 *mExtEditorProcess << sysLine.left(sysLine.find(
" ")).local8Bit();
05885 sysLine.remove(0, sysLine.find(
" ") + 1);
05886 }
05887 connect(mExtEditorProcess, SIGNAL(processExited(KProcess*)),
05888 SLOT(slotExternalEditorDone(KProcess*)));
05889
if (!mExtEditorProcess->start())
05890 {
05891 KMessageBox::error( topLevelWidget(),
05892 i18n(
"Unable to start external editor.") );
05893 killExternalEditor();
05894 }
else {
05895 mExtEditorTempFileWatcher =
new KDirWatch(
this,
"mExtEditorTempFileWatcher" );
05896 connect( mExtEditorTempFileWatcher, SIGNAL(dirty(
const QString&)),
05897 SLOT(slotExternalEditorTempFileChanged(
const QString&)) );
05898 mExtEditorTempFileWatcher->addFile( mExtEditorTempFile->name() );
05899 }
05900
return TRUE;
05901 }
else {
05902
05903
05904
if (k->key() == Key_Up && k->state() != ShiftButton && currentLine() == 0
05905 && lineOfChar(0, currentColumn()) == 0)
05906 {
05907 deselect();
05908 mComposer->focusNextPrevEdit(0,
false);
05909
return TRUE;
05910 }
05911
05912
05913
if (k->key() == Key_Backtab && k->state() == ShiftButton)
05914 {
05915 deselect();
05916 mComposer->focusNextPrevEdit(0,
false);
05917
return TRUE;
05918 }
05919
05920 }
05921 }
else if ( e->type() == QEvent::ContextMenu ) {
05922 QContextMenuEvent *event = (QContextMenuEvent*) e;
05923
05924
int para = 1, charPos, firstSpace, lastSpace;
05925
05926
05927 charPos = charAt( viewportToContents(event->pos()), ¶ );
05928 QString paraText = text( para );
05929
05930
if( !paraText.at(charPos).isSpace() )
05931 {
05932
05933
const QRegExp wordBoundary(
"[\\s\\W]" );
05934 firstSpace = paraText.findRev( wordBoundary, charPos ) + 1;
05935 lastSpace = paraText.find( wordBoundary, charPos );
05936
if( lastSpace == -1 )
05937 lastSpace = paraText.length();
05938 QString word = paraText.mid( firstSpace, lastSpace - firstSpace );
05939
05940
if( !word.isEmpty() && mReplacements.contains( word ) )
05941 {
05942 KPopupMenu p;
05943 p.insertTitle( i18n(
"Suggestions") );
05944
05945
05946 QStringList reps = mReplacements[word];
05947
if( reps.count() > 0 )
05948 {
05949
int listPos = 0;
05950
for ( QStringList::Iterator it = reps.begin(); it != reps.end(); ++it ) {
05951 p.insertItem( *it, listPos );
05952 listPos++;
05953 }
05954 }
05955
else
05956 {
05957 p.insertItem( QString::fromLatin1(
"No Suggestions"), -2 );
05958 }
05959
05960
05961
int id = p.exec( mapToGlobal( event->pos() ) );
05962
05963
if(
id > -1 )
05964 {
05965
05966
int parIdx = 1, txtIdx = 1;
05967 getCursorPosition(&parIdx, &txtIdx);
05968 setSelection(para, firstSpace, para, lastSpace);
05969 insert(mReplacements[word][
id]);
05970
05971
05972
if ( para == parIdx && txtIdx >= lastSpace )
05973 txtIdx += mReplacements[word][
id].length() - word.length();
05974 setCursorPosition(parIdx, txtIdx);
05975 }
05976
05977
return true;
05978 }
05979 }
05980 }
05981
05982
return KEdit::eventFilter(o, e);
05983 }
05984
05985
05986
05987
void KMEdit::slotAutoSpellCheckingToggled(
bool on )
05988 {
05989
05990 mSpellChecker->setAutomatic( on );
05991 mSpellChecker->setActive( on );
05992 }
05993
05994
05995
05996
void KMEdit::slotExternalEditorTempFileChanged(
const QString & fileName ) {
05997
if ( !mExtEditorTempFile )
05998
return;
05999
if ( fileName != mExtEditorTempFile->name() )
06000
return;
06001
06002 setAutoUpdate(
false);
06003 clear();
06004
06005 insertLine(QString::fromLocal8Bit(kFileToString( fileName,
true,
false )), -1);
06006 setAutoUpdate(
true);
06007 repaint();
06008 }
06009
06010
void KMEdit::slotExternalEditorDone( KProcess * proc ) {
06011 assert(proc == mExtEditorProcess);
06012
06013 slotExternalEditorTempFileChanged( mExtEditorTempFile->name() );
06014 killExternalEditor();
06015 }
06016
06017
void KMEdit::killExternalEditor() {
06018
delete mExtEditorTempFileWatcher; mExtEditorTempFileWatcher = 0;
06019
delete mExtEditorTempFile; mExtEditorTempFile = 0;
06020
delete mExtEditorProcess; mExtEditorProcess = 0;
06021 }
06022
06023
06024
bool KMEdit::checkExternalEditorFinished() {
06025
if ( !mExtEditorProcess )
06026
return true;
06027
switch ( KMessageBox::warningYesNoCancel( topLevelWidget(),
06028 i18n(
"The external editor is still running.\n"
06029
"Abort the external editor or leave it open?"),
06030 i18n(
"External Editor"),
06031 i18n(
"Abort Editor"), i18n(
"Leave Editor Open") ) ) {
06032
case KMessageBox::Yes:
06033 killExternalEditor();
06034
return true;
06035
case KMessageBox::No:
06036
return true;
06037
default:
06038
return false;
06039 }
06040 }
06041
06042
06043
void KMEdit::spellcheck()
06044 {
06045
if ( mKSpell )
06046
return;
06047 mWasModifiedBeforeSpellCheck = isModified();
06048 mSpellLineEdit = !mSpellLineEdit;
06049 mKSpell =
new KSpell(
this, i18n(
"Spellcheck - KMail"),
this,
06050 SLOT(slotSpellcheck2(KSpell*)));
06051 QStringList l = KSpellingHighlighter::personalWords();
06052
for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
06053 mKSpell->addPersonal( *it );
06054 }
06055 connect (mKSpell, SIGNAL( death()),
06056
this, SLOT (slotSpellDone()));
06057 connect (mKSpell, SIGNAL (misspelling (
const QString &,
const QStringList &,
unsigned int)),
06058
this, SLOT (slotMisspelling (
const QString &,
const QStringList &,
unsigned int)));
06059 connect (mKSpell, SIGNAL (corrected (
const QString &,
const QString &,
unsigned int)),
06060
this, SLOT (slotCorrected (
const QString &,
const QString &,
unsigned int)));
06061 connect (mKSpell, SIGNAL (done(
const QString &)),
06062
this, SLOT (slotSpellResult (
const QString&)));
06063 }
06064
06065
#if KDE_IS_VERSION( 3, 1, 92 )
06066
void KMEdit::cut()
06067 {
06068 KEdit::cut();
06069 mSpellChecker->restartBackgroundSpellCheck();
06070 }
06071
06072
void KMEdit::clear()
06073 {
06074 KEdit::clear();
06075 mSpellChecker->restartBackgroundSpellCheck();
06076 }
06077
06078
void KMEdit::del()
06079 {
06080 KEdit::del();
06081 mSpellChecker->restartBackgroundSpellCheck();
06082 }
06083
#else
06084
06085
void KMEdit::cut() { KEdit::cut(); }
06086
void KMEdit::clear() { KEdit::clear(); }
06087
void KMEdit::del() { KEdit::del(); }
06088
#endif
06089
06090
06091
void KMEdit::slotMisspelling(
const QString &text,
const QStringList &lst,
unsigned int pos)
06092 {
06093 kdDebug()<<
"void KMEdit::slotMisspelling(const QString &text, const QStringList &lst, unsigned int pos) : "<<text <<endl;
06094
if( mSpellLineEdit )
06095 mComposer->sujectLineWidget()->spellCheckerMisspelling( text, lst, pos);
06096
else
06097 misspelling(text, lst, pos);
06098 }
06099
06100
void KMEdit::slotCorrected (
const QString &oldWord,
const QString &newWord,
unsigned int pos)
06101 {
06102 kdDebug()<<
"slotCorrected (const QString &oldWord, const QString &newWord, unsigned int pos) : "<<oldWord<<endl;
06103
if( mSpellLineEdit )
06104 mComposer->sujectLineWidget()->spellCheckerCorrected( oldWord, newWord, pos);
06105
else
06106 corrected(oldWord, newWord, pos);
06107 }
06108
06109
06110
void KMEdit::slotSpellcheck2(KSpell*)
06111 {
06112
if( !mSpellLineEdit)
06113 {
06114 spellcheck_start();
06115
06116 QString quotePrefix;
06117
if(mComposer && mComposer->msg())
06118 {
06119
06120 KConfig *config=KMKernel::config();
06121 KConfigGroupSaver saver(config,
"General");
06122
06123
int languageNr = config->readNumEntry(
"reply-current-language",0);
06124 config->setGroup( QString(
"KMMessage #%1").arg(languageNr) );
06125
06126 quotePrefix = config->readEntry(
"indent-prefix",
">%_");
06127 quotePrefix = mComposer->msg()->formatString(quotePrefix);
06128 }
06129
06130 kdDebug(5006) <<
"spelling: new SpellingFilter with prefix=\"" << quotePrefix <<
"\"" << endl;
06131 mSpellingFilter =
new SpellingFilter(text(), quotePrefix, SpellingFilter::FilterUrls,
06132 SpellingFilter::FilterEmailAddresses);
06133
06134 mKSpell->check(mSpellingFilter->filteredText());
06135 }
06136
else if( mComposer )
06137 mKSpell->check( mComposer->sujectLineWidget()->text());
06138 }
06139
06140
06141
void KMEdit::slotSpellResult(
const QString &s)
06142 {
06143
if( !mSpellLineEdit)
06144 spellcheck_stop();
06145
06146
int dlgResult = mKSpell->dlgResult();
06147
if ( dlgResult == KS_CANCEL )
06148 {
06149
if( mSpellLineEdit)
06150 {
06151
06152 mSpellLineEdit =
false;
06153 QString tmpText( s );
06154 tmpText = tmpText.remove(
'\n');
06155
06156
if( tmpText != mComposer->sujectLineWidget()->text() )
06157 mComposer->sujectLineWidget()->setText( tmpText );
06158 }
06159
else
06160 {
06161 kdDebug(5006) <<
"spelling: canceled - restoring text from SpellingFilter" << endl;
06162 setText(mSpellingFilter->originalText());
06163 setModified(mWasModifiedBeforeSpellCheck);
06164 }
06165 }
06166 mKSpell->cleanUp();
06167 KDictSpellingHighlighter::dictionaryChanged();
06168
06169 emit spellcheck_done( dlgResult );
06170 }
06171
06172
06173
void KMEdit::slotSpellDone()
06174 {
06175 kdDebug()<<
" void KMEdit::slotSpellDone()**********************************************\n";
06176 KSpell::spellStatus status = mKSpell->status();
06177
delete mKSpell;
06178 mKSpell = 0;
06179
06180 kdDebug() <<
"spelling: delete SpellingFilter" << endl;
06181
delete mSpellingFilter;
06182 mSpellingFilter = 0;
06183 mComposer->sujectLineWidget()->deselect();
06184
if (status == KSpell::Error)
06185 {
06186 KMessageBox::sorry( topLevelWidget(),
06187 i18n(
"ISpell/Aspell could not be started. Please "
06188
"make sure you have ISpell or Aspell properly "
06189
"configured and in your PATH.") );
06190 emit spellcheck_done( KS_CANCEL );
06191 }
06192
else if (status == KSpell::Crashed)
06193 {
06194 spellcheck_stop();
06195 KMessageBox::sorry( topLevelWidget(),
06196 i18n(
"ISpell/Aspell seems to have crashed.") );
06197 emit spellcheck_done( KS_CANCEL );
06198 }
06199
else
06200 {
06201
if( mSpellLineEdit )
06202 spellcheck();
06203
#if KDE_IS_VERSION( 3, 1, 90 )
06204
else if( status == KSpell::FinishedNoMisspellingsEncountered )
06205 KMessageBox::information( topLevelWidget(),
06206 i18n(
"No misspellings encountered.") );
06207
#endif
06208
}
06209 }