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 ", "@" );
newText.replace( " dot ", "." );
05695 }
05696 else if (newText.contains("(at)"))
05697 {
05698 newText.replace( QRegExp("\\s*\\(at\\)\\s*"), "@" );
}
contents = contents.left(pos)+newText+contents.mid(pos);
setText(contents);
setEdited( true );
setCursorPosition(pos+newText.length());
}
#endif
//-----------------------------------------------------------------------------
void KMLineEdit::loadAddresses()
{
AddressLineEdit::loadAddresses();
QStringList recent = RecentAddresses::self(KMKernel::config())->addresses();
QStringList::Iterator it = recent.begin();
for ( ; it != recent.end(); ++it )
addAddress( *it );
}
KMLineEditSpell::KMLineEditSpell(KMComposeWin* composer, bool useCompletion,
QWidget *parent, const char *name)
: KMLineEdit(composer,useCompletion,parent,name)
{
}
void KMLineEditSpell::highLightWord( unsigned int length, unsigned int pos )
{
setSelection ( pos, length );
}
void KMLineEditSpell::spellCheckDone( const QString &s )
{
if( s != text() )
setText( s );
}
void KMLineEditSpell::spellCheckerMisspelling( const QString &_text, const QStringList&, unsigned int pos)
{
highLightWord( _text.length(),pos );
}
void KMLineEditSpell::spellCheckerCorrected( const QString &old, const QString &corr, unsigned int pos)
{
if( old!= corr )
{
setSelection ( pos, old.length() );
insert( corr );
setSelection ( pos, corr.length() );
}
}
//=============================================================================
//
// Class KMEdit
//
//=============================================================================
KMEdit::KMEdit(QWidget *parent, KMComposeWin* composer,
KSpellConfig* autoSpellConfig,
const char *name)
: KEdit( parent, name ),
mComposer( composer ),
mKSpell( 0 ),
mSpellingFilter( 0 ),
mExtEditorTempFile( 0 ),
mExtEditorTempFileWatcher( 0 ),
mExtEditorProcess( 0 ),
mUseExtEditor( false ),
mWasModifiedBeforeSpellCheck( false ),
mSpellChecker( 0 ),
mSpellLineEdit( false )
{
installEventFilter(this);
KCursor::setAutoHideCursor( this, true, true );
initializeAutoSpellChecking( autoSpellConfig );
}
//-----------------------------------------------------------------------------
void KMEdit::initializeAutoSpellChecking( KSpellConfig* autoSpellConfig )
{
KConfigGroup readerConfig( KMKernel::config(), "Reader" );
05699 QColor defaultColor1( 0x00, 0x80, 0x00 );
05700 QColor defaultColor2( 0x00, 0x70, 0x00 );
05701 QColor defaultColor3( 0x00, 0x60, 0x00 );
05702 QColor defaultForeground( kapp->palette().active().text() );
05703 QColor col1 = readerConfig.readColorEntry( "ForegroundColor", &defaultForeground );
05704 QColor col2 = readerConfig.readColorEntry( "QuotedText3", &defaultColor3 );
05705 QColor col3 = readerConfig.readColorEntry( "QuotedText2", &defaultColor2 );
05706 QColor col4 = readerConfig.readColorEntry( "QuotedText1", &defaultColor1 );
05707 QColor c = Qt::red;
05708 QColor misspelled = readerConfig.readColorEntry( "MisspelledColor", &c );
05709
05710 mSpellChecker = new KDictSpellingHighlighter( this, true,
05711 false,
05712 misspelled,
05713 true,
05714 col1, col2, col3, col4,
05715 autoSpellConfig );
05716 connect( mSpellChecker, SIGNAL(activeChanged(const QString &)),
05717 mComposer, SLOT(slotStatusMessage(const QString &)));
05718 connect( mSpellChecker, SIGNAL(newSuggestions(const QString&, const QStringList&, unsigned int)),
05719 this, SLOT(addSuggestion(const QString&, const QStringList&, unsigned int)) );
05720 }
05721
05722
05723 void KMEdit::addSuggestion(const QString& text, const QStringList& lst, unsigned int )
05724 {
05725 mReplacements[text] = lst;
05726 }
05727
05728
05729 KMEdit::~KMEdit()
05730 {
05731 removeEventFilter(this);
05732
05733 delete mKSpell;
05734 delete mSpellChecker;
05735 }
05736
05737
05738
05739 QString KMEdit::brokenText()
05740 {
05741 QString temp, line;
05742
05743 int num_lines = numLines();
05744 for (int i = 0; i < num_lines; ++i)
05745 {
05746 int lastLine = 0;
05747 line = textLine(i);
05748 for (int j = 0; j < (int)line.length(); ++j)
05749 {
05750 if (lineOfChar(i, j) > lastLine)
05751 {
05752 lastLine = lineOfChar(i, j);
05753 temp += '\n';
05754 }
05755 temp += line[j];
05756 }
05757 if (i + 1 < num_lines) temp += '\n';
05758 }
05759
05760 return temp;
05761 }
05762
05763
05764 bool KMEdit::eventFilter(QObject*o, QEvent* e)
05765 {
05766 if (o == this)
05767 KCursor::autoHideEventFilter(o, e);
05768
05769 if (e->type() == QEvent::KeyPress)
05770 {
05771 QKeyEvent *k = (QKeyEvent*)e;
05772
05773 if (mUseExtEditor) {
05774 if (k->key() == Key_Up)
05775 {
05776 mComposer->focusNextPrevEdit(0, false);
05777 return TRUE;
05778 }
05779
05780
05781 if ( (k->key() == Key_Shift) || (k->key() == Key_Control) ||
05782 (k->key() == Key_Meta) || (k->key() == Key_Alt) )
05783 return true;
05784 if (mExtEditorTempFile) return TRUE;
05785 QString sysLine = mExtEditor;
05786 mExtEditorTempFile = new KTempFile();
05787
05788 mExtEditorTempFile->setAutoDelete(true);
05789
05790 (*mExtEditorTempFile->textStream()) << text();
05791
05792 mExtEditorTempFile->close();
05793
05794 sysLine.replace( "%f", mExtEditorTempFile->name() );
05795 mExtEditorProcess = new KProcess();
05796 sysLine += " ";
05797 while (!sysLine.isEmpty())
05798 {
05799 *mExtEditorProcess << sysLine.left(sysLine.find(" ")).local8Bit();
05800 sysLine.remove(0, sysLine.find(" ") + 1);
05801 }
05802 connect(mExtEditorProcess, SIGNAL(processExited(KProcess*)),
05803 SLOT(slotExternalEditorDone(KProcess*)));
05804 if (!mExtEditorProcess->start())
05805 {
05806 KMessageBox::error( topLevelWidget(),
05807 i18n("Unable to start external editor.") );
05808 killExternalEditor();
05809 } else {
05810 mExtEditorTempFileWatcher = new KDirWatch( this, "mExtEditorTempFileWatcher" );
05811 connect( mExtEditorTempFileWatcher, SIGNAL(dirty(const QString&)),
05812 SLOT(slotExternalEditorTempFileChanged(const QString&)) );
05813 mExtEditorTempFileWatcher->addFile( mExtEditorTempFile->name() );
05814 }
05815 return TRUE;
05816 } else {
05817
05818
05819 if (k->key() == Key_Up && k->state() != ShiftButton && currentLine() == 0
05820 && lineOfChar(0, currentColumn()) == 0)
05821 {
05822 deselect();
05823 mComposer->focusNextPrevEdit(0, false);
05824 return TRUE;
05825 }
05826
05827
05828 if (k->key() == Key_Backtab && k->state() == ShiftButton)
05829 {
05830 deselect();
05831 mComposer->focusNextPrevEdit(0, false);
05832 return TRUE;
05833 }
05834
05835 }
05836 } else if ( e->type() == QEvent::ContextMenu ) {
05837 QContextMenuEvent *event = (QContextMenuEvent*) e;
05838
05839 int para = 1, charPos, firstSpace, lastSpace;
05840
05841
05842 charPos = charAt( viewportToContents(event->pos()), ¶ );
05843 QString paraText = text( para );
05844
05845 if( !paraText.at(charPos).isSpace() )
05846 {
05847
05848 const QRegExp wordBoundary( "[\\s\\W]" );
05849 firstSpace = paraText.findRev( wordBoundary, charPos ) + 1;
05850 lastSpace = paraText.find( wordBoundary, charPos );
05851 if( lastSpace == -1 )
05852 lastSpace = paraText.length();
05853 QString word = paraText.mid( firstSpace, lastSpace - firstSpace );
05854
05855 if( !word.isEmpty() && mReplacements.contains( word ) )
05856 {
05857 KPopupMenu p;
05858 p.insertTitle( i18n("Suggestions") );
05859
05860
05861 QStringList reps = mReplacements[word];
05862 if( reps.count() > 0 )
05863 {
05864 int listPos = 0;
05865 for ( QStringList::Iterator it = reps.begin(); it != reps.end(); ++it ) {
05866 p.insertItem( *it, listPos );
05867 listPos++;
05868 }
05869 }
05870 else
05871 {
05872 p.insertItem( QString::fromLatin1("No Suggestions"), -2 );
05873 }
05874
05875
05876 int id = p.exec( mapToGlobal( event->pos() ) );
05877
05878 if( id > -1 )
05879 {
05880
05881 int parIdx = 1, txtIdx = 1;
05882 getCursorPosition(&parIdx, &txtIdx);
05883 setSelection(para, firstSpace, para, lastSpace);
05884 insert(mReplacements[word][id]);
05885
05886
05887 if ( para == parIdx && txtIdx >= lastSpace )
05888 txtIdx += mReplacements[word][id].length() - word.length();
05889 setCursorPosition(parIdx, txtIdx);
05890 }
05891
05892 return true;
05893 }
05894 }
05895 }
05896
05897 return KEdit::eventFilter(o, e);
05898 }
05899
05900
05901
05902 void KMEdit::slotAutoSpellCheckingToggled( bool on )
05903 {
05904
05905 mSpellChecker->setAutomatic( on );
05906 mSpellChecker->setActive( on );
05907 }
05908
05909
05910
05911 void KMEdit::slotExternalEditorTempFileChanged( const QString & fileName ) {
05912 if ( !mExtEditorTempFile )
05913 return;
05914 if ( fileName != mExtEditorTempFile->name() )
05915 return;
05916
05917 setAutoUpdate(false);
05918 clear();
05919
05920 insertLine(QString::fromLocal8Bit(kFileToString( fileName, true, false )), -1);
05921 setAutoUpdate(true);
05922 repaint();
05923 }
05924
05925 void KMEdit::slotExternalEditorDone( KProcess * proc ) {
05926 assert(proc == mExtEditorProcess);
05927
05928 slotExternalEditorTempFileChanged( mExtEditorTempFile->name() );
05929 killExternalEditor();
05930 }
05931
05932 void KMEdit::killExternalEditor() {
05933 delete mExtEditorTempFileWatcher; mExtEditorTempFileWatcher = 0;
05934 delete mExtEditorTempFile; mExtEditorTempFile = 0;
05935 delete mExtEditorProcess; mExtEditorProcess = 0;
05936 }
05937
05938
05939 bool KMEdit::checkExternalEditorFinished() {
05940 if ( !mExtEditorProcess )
05941 return true;
05942 switch ( KMessageBox::warningYesNoCancel( topLevelWidget(),
05943 i18n("The external editor is still running.\n"
05944 "Abort the external editor or leave it open?"),
05945 i18n("External Editor"),
05946 i18n("Abort Editor"), i18n("Leave Editor Open") ) ) {
05947 case KMessageBox::Yes:
05948 killExternalEditor();
05949 return true;
05950 case KMessageBox::No:
05951 return true;
05952 default:
05953 return false;
05954 }
05955 }
05956
05957
05958 void KMEdit::spellcheck()
05959 {
05960 if ( mKSpell )
05961 return;
05962 mWasModifiedBeforeSpellCheck = isModified();
05963 mSpellLineEdit = !mSpellLineEdit;
05964 mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
05965 SLOT(slotSpellcheck2(KSpell*)));
05966 QStringList l = KSpellingHighlighter::personalWords();
05967 for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
05968 mKSpell->addPersonal( *it );
05969 }
05970 connect (mKSpell, SIGNAL( death()),
05971 this, SLOT (slotSpellDone()));
05972 connect (mKSpell, SIGNAL (misspelling (const QString &, const QStringList &, unsigned int)),
05973 this, SLOT (slotMisspelling (const QString &, const QStringList &, unsigned int)));
05974 connect (mKSpell, SIGNAL (corrected (const QString &, const QString &, unsigned int)),
05975 this, SLOT (slotCorrected (const QString &, const QString &, unsigned int)));
05976 connect (mKSpell, SIGNAL (done(const QString &)),
05977 this, SLOT (slotSpellResult (const QString&)));
05978 }
05979
05980 #if KDE_IS_VERSION( 3, 1, 92 )
05981 void KMEdit::cut()
05982 {
05983 KEdit::cut();
05984 mSpellChecker->restartBackgroundSpellCheck();
05985 }
05986
05987 void KMEdit::clear()
05988 {
05989 KEdit::clear();
05990 mSpellChecker->restartBackgroundSpellCheck();
05991 }
05992
05993 void KMEdit::del()
05994 {
05995 KEdit::del();
05996 mSpellChecker->restartBackgroundSpellCheck();
05997 }
05998 #else
05999
06000 void KMEdit::cut() { KEdit::cut(); }
06001 void KMEdit::clear() { KEdit::clear(); }
06002 void KMEdit::del() { KEdit::del(); }
06003 #endif
06004
06005
06006 void KMEdit::slotMisspelling(const QString &text, const QStringList &lst, unsigned int pos)
06007 {
06008 kdDebug()<<"void KMEdit::slotMisspelling(const QString &text, const QStringList &lst, unsigned int pos) : "<<text <<endl;
06009 if( mSpellLineEdit )
06010 mComposer->sujectLineWidget()->spellCheckerMisspelling( text, lst, pos);
06011 else
06012 misspelling(text, lst, pos);
06013 }
06014
06015 void KMEdit::slotCorrected (const QString &oldWord, const QString &newWord, unsigned int pos)
06016 {
06017 kdDebug()<<"slotCorrected (const QString &oldWord, const QString &newWord, unsigned int pos) : "<<oldWord<<endl;
06018 if( mSpellLineEdit )
06019 mComposer->sujectLineWidget()->spellCheckerCorrected( oldWord, newWord, pos);
06020 else
06021 corrected(oldWord, newWord, pos);
06022 }
06023
06024
06025 void KMEdit::slotSpellcheck2(KSpell*)
06026 {
06027 if( !mSpellLineEdit)
06028 {
06029 spellcheck_start();
06030
06031 QString quotePrefix;
06032 if(mComposer && mComposer->msg())
06033 {
06034
06035 KConfig *config=KMKernel::config();
06036 KConfigGroupSaver saver(config, "General");
06037
06038 int languageNr = config->readNumEntry("reply-current-language",0);
06039 config->setGroup( QString("KMMessage #%1").arg(languageNr) );
06040
06041 quotePrefix = config->readEntry("indent-prefix", ">%_");
06042 quotePrefix = mComposer->msg()->formatString(quotePrefix);
06043 }
06044
06045 kdDebug(5006) << "spelling: new SpellingFilter with prefix=\"" << quotePrefix << "\"" << endl;
06046 mSpellingFilter = new SpellingFilter(text(), quotePrefix, SpellingFilter::FilterUrls,
06047 SpellingFilter::FilterEmailAddresses);
06048
06049 mKSpell->check(mSpellingFilter->filteredText());
06050 }
06051 else if( mComposer )
06052 mKSpell->check( mComposer->sujectLineWidget()->text());
06053 }
06054
06055
06056 void KMEdit::slotSpellResult(const QString &s)
06057 {
06058 if( !mSpellLineEdit)
06059 spellcheck_stop();
06060
06061 int dlgResult = mKSpell->dlgResult();
06062 if ( dlgResult == KS_CANCEL )
06063 {
06064 if( mSpellLineEdit)
06065 {
06066
06067 mSpellLineEdit = false;
06068 QString tmpText( s );
06069 tmpText = tmpText.remove('\n');
06070
06071 if( tmpText != mComposer->sujectLineWidget()->text() )
06072 mComposer->sujectLineWidget()->setText( tmpText );
06073 }
06074 else
06075 {
06076 kdDebug(5006) << "spelling: canceled - restoring text from SpellingFilter" << endl;
06077 setText(mSpellingFilter->originalText());
06078 setModified(mWasModifiedBeforeSpellCheck);
06079 }
06080 }
06081 mKSpell->cleanUp();
06082 KDictSpellingHighlighter::dictionaryChanged();
06083
06084 emit spellcheck_done( dlgResult );
06085 }
06086
06087
06088 void KMEdit::slotSpellDone()
06089 {
06090 kdDebug()<<" void KMEdit::slotSpellDone()**********************************************\n";
06091 KSpell::spellStatus status = mKSpell->status();
06092 delete mKSpell;
06093 mKSpell = 0;
06094
06095 kdDebug() << "spelling: delete SpellingFilter" << endl;
06096 delete mSpellingFilter;
06097 mSpellingFilter = 0;
06098 mComposer->sujectLineWidget()->deselect();
06099 if (status == KSpell::Error)
06100 {
06101 KMessageBox::sorry( topLevelWidget(),
06102 i18n("ISpell/Aspell could not be started. Please "
06103 "make sure you have ISpell or Aspell properly "
06104 "configured and in your PATH.") );
06105 emit spellcheck_done( KS_CANCEL );
06106 }
06107 else if (status == KSpell::Crashed)
06108 {
06109 spellcheck_stop();
06110 KMessageBox::sorry( topLevelWidget(),
06111 i18n("ISpell/Aspell seems to have crashed.") );
06112 emit spellcheck_done( KS_CANCEL );
06113 }
06114 else
06115 {
06116 if( mSpellLineEdit )
06117 spellcheck();
06118 #if KDE_IS_VERSION( 3, 1, 90 )
06119 else if( status == KSpell::FinishedNoMisspellingsEncountered )
06120 KMessageBox::information( topLevelWidget(),
06121 i18n("No misspellings encountered.") );
06122 #endif
06123 }
06124 }
06125