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