00001
00002
00003
00004
00005
00006 #undef GrayScale
00007 #undef Color
00008 #include <config.h>
00009
00010 #define REALLY_WANT_KMCOMPOSEWIN_H
00011 #include "kmcomposewin.h"
00012 #undef REALLY_WANT_KMCOMPOSEWIN_H
00013
00014 #include "kmedit.h"
00015 #include "kmlineeditspell.h"
00016 #include "kmatmlistview.h"
00017
00018 #include "kmmainwin.h"
00019 #include "kmreadermainwin.h"
00020 #include "messagesender.h"
00021 #include "kmmsgpartdlg.h"
00022 #include <kpgpblock.h>
00023 #include <kaddrbook.h>
00024 #include "kmaddrbook.h"
00025 #include "kmmsgdict.h"
00026 #include "kmfolderimap.h"
00027 #include "kmfoldermgr.h"
00028 #include "kmfoldercombobox.h"
00029 #include "kmtransport.h"
00030 #include "kmcommands.h"
00031 #include "kcursorsaver.h"
00032 #include "partNode.h"
00033 #include "attachmentlistview.h"
00034 #include "transportmanager.h"
00035 using KMail::AttachmentListView;
00036 #include "dictionarycombobox.h"
00037 using KMail::DictionaryComboBox;
00038 #include "addressesdialog.h"
00039 using KPIM::AddressesDialog;
00040 #include "addresseeemailselection.h"
00041 using KPIM::AddresseeEmailSelection;
00042 using KPIM::AddresseeSelectorDialog;
00043 #include <maillistdrag.h>
00044 using KPIM::MailListDrag;
00045 #include "recentaddresses.h"
00046 using KRecentAddress::RecentAddresses;
00047 #include "kleo_util.h"
00048 #include "stl_util.h"
00049 #include "recipientseditor.h"
00050
00051 #include "attachmentcollector.h"
00052 #include "objecttreeparser.h"
00053
00054 #include "kmfoldermaildir.h"
00055
00056 #include <libkpimidentities/identitymanager.h>
00057 #include <libkpimidentities/identitycombo.h>
00058 #include <libkpimidentities/identity.h>
00059 #include <libkdepim/kfileio.h>
00060 #include <libemailfunctions/email.h>
00061 #include <kleo/cryptobackendfactory.h>
00062 #include <kleo/exportjob.h>
00063 #include <kleo/specialjob.h>
00064 #include <ui/progressdialog.h>
00065 #include <ui/keyselectiondialog.h>
00066
00067 #include <gpgmepp/context.h>
00068 #include <gpgmepp/key.h>
00069
00070 #include <kabc/vcardconverter.h>
00071 #include <libkdepim/kvcarddrag.h>
00072 #include <kio/netaccess.h>
00073
00074
00075 #include "klistboxdialog.h"
00076
00077 #include "messagecomposer.h"
00078 #include "chiasmuskeyselector.h"
00079
00080 #include <kcharsets.h>
00081 #include <kcompletionbox.h>
00082 #include <kcursor.h>
00083 #include <kcombobox.h>
00084 #include <kstdaccel.h>
00085 #include <kpopupmenu.h>
00086 #include <kedittoolbar.h>
00087 #include <kkeydialog.h>
00088 #include <kdebug.h>
00089 #include <kfiledialog.h>
00090 #include <kwin.h>
00091 #include <kinputdialog.h>
00092 #include <kmessagebox.h>
00093 #include <kurldrag.h>
00094 #include <kio/scheduler.h>
00095 #include <ktempfile.h>
00096 #include <klocale.h>
00097 #include <kapplication.h>
00098 #include <kstatusbar.h>
00099 #include <kaction.h>
00100 #include <kstdaction.h>
00101 #include <kdirwatch.h>
00102 #include <kstdguiitem.h>
00103 #include <kiconloader.h>
00104 #include <kpushbutton.h>
00105 #include <kuserprofile.h>
00106 #include <krun.h>
00107 #include <ktempdir.h>
00108
00109 #include "globalsettings.h"
00110 #include "replyphrases.h"
00111
00112 #include <kspell.h>
00113 #include <kspelldlg.h>
00114 #include <spellingfilter.h>
00115 #include <ksyntaxhighlighter.h>
00116 #include <kcolordialog.h>
00117 #include <kzip.h>
00118 #include <ksavefile.h>
00119
00120 #include <qtabdialog.h>
00121 #include <qregexp.h>
00122 #include <qbuffer.h>
00123 #include <qtooltip.h>
00124 #include <qtextcodec.h>
00125 #include <qheader.h>
00126 #include <qwhatsthis.h>
00127 #include <qfontdatabase.h>
00128
00129 #include <mimelib/mimepp.h>
00130
00131 #include <algorithm>
00132 #include <memory>
00133
00134 #include <sys/stat.h>
00135 #include <sys/types.h>
00136 #include <stdlib.h>
00137 #include <unistd.h>
00138 #include <errno.h>
00139 #include <fcntl.h>
00140 #include <assert.h>
00141
00142 #include "kmcomposewin.moc"
00143
00144 KMail::Composer * KMail::makeComposer( KMMessage * msg, uint identitiy ) {
00145 return KMComposeWin::create( msg, identitiy );
00146 }
00147
00148 KMail::Composer * KMComposeWin::create( KMMessage * msg, uint identitiy ) {
00149 return new KMComposeWin( msg, identitiy );
00150 }
00151
00152
00153 KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
00154 : MailComposerIface(), KMail::Composer( "kmail-composer#" ),
00155 mSpellCheckInProgress( false ),
00156 mDone( false ),
00157 mAtmModified( false ),
00158 mMsg( 0 ),
00159 mAttachMenu( 0 ),
00160 mSigningAndEncryptionExplicitlyDisabled( false ),
00161 mFolder( 0 ),
00162 mUseHTMLEditor( false ),
00163 mId( id ),
00164 mAttachPK( 0 ), mAttachMPK( 0 ),
00165 mAttachRemoveAction( 0 ), mAttachSaveAction( 0 ), mAttachPropertiesAction( 0 ),
00166 mSignAction( 0 ), mEncryptAction( 0 ), mRequestMDNAction( 0 ),
00167 mUrgentAction( 0 ), mAllFieldsAction( 0 ), mFromAction( 0 ),
00168 mReplyToAction( 0 ), mToAction( 0 ), mCcAction( 0 ), mBccAction( 0 ),
00169 mSubjectAction( 0 ),
00170 mIdentityAction( 0 ), mTransportAction( 0 ), mFccAction( 0 ),
00171 mWordWrapAction( 0 ), mFixedFontAction( 0 ), mAutoSpellCheckingAction( 0 ),
00172 mDictionaryAction( 0 ),
00173 mEncodingAction( 0 ),
00174 mCryptoModuleAction( 0 ),
00175 mEncryptChiasmusAction( 0 ),
00176 mEncryptWithChiasmus( false ),
00177 mComposer( 0 ),
00178 mLabelWidth( 0 ),
00179 mAutoSaveTimer( 0 ), mLastAutoSaveErrno( 0 )
00180 {
00181 mClassicalRecipients = GlobalSettings::self()->recipientsEditorType() ==
00182 GlobalSettings::EnumRecipientsEditorType::Classic;
00183
00184 mSubjectTextWasSpellChecked = false;
00185 if (kmkernel->xmlGuiInstance())
00186 setInstance( kmkernel->xmlGuiInstance() );
00187 mMainWidget = new QWidget(this);
00188 mIdentity = new KPIM::IdentityCombo(kmkernel->identityManager(), mMainWidget);
00189 mDictionaryCombo = new DictionaryComboBox( mMainWidget );
00190 mFcc = new KMFolderComboBox(mMainWidget);
00191 mFcc->showOutboxFolder( FALSE );
00192 mTransport = new QComboBox(true, mMainWidget);
00193 mEdtFrom = new KMLineEdit(false,mMainWidget, "fromLine");
00194
00195 mEdtReplyTo = new KMLineEdit(true,mMainWidget, "replyToLine");
00196 mLblReplyTo = new QLabel(mMainWidget);
00197 mBtnReplyTo = new QPushButton("...",mMainWidget);
00198 mBtnReplyTo->setFocusPolicy(QWidget::NoFocus);
00199 connect(mBtnReplyTo,SIGNAL(clicked()),SLOT(slotAddrBookReplyTo()));
00200 connect(mEdtReplyTo,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00201 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00202
00203 if ( mClassicalRecipients ) {
00204 mRecipientsEditor = 0;
00205
00206 mEdtTo = new KMLineEdit(true,mMainWidget, "toLine");
00207 mEdtCc = new KMLineEdit(true,mMainWidget, "ccLine");
00208 mEdtBcc = new KMLineEdit(true,mMainWidget, "bccLine");
00209
00210 mLblTo = new QLabel(mMainWidget);
00211 mLblCc = new QLabel(mMainWidget);
00212 mLblBcc = new QLabel(mMainWidget);
00213
00214 mBtnTo = new QPushButton("...",mMainWidget);
00215 mBtnCc = new QPushButton("...",mMainWidget);
00216 mBtnBcc = new QPushButton("...",mMainWidget);
00217
00218
00219 QString tip = i18n("Select email address(es)");
00220 QToolTip::add( mBtnTo, tip );
00221 QToolTip::add( mBtnCc, tip );
00222 QToolTip::add( mBtnBcc, tip );
00223 QToolTip::add( mBtnReplyTo, tip );
00224
00225 mBtnTo->setFocusPolicy(QWidget::NoFocus);
00226 mBtnCc->setFocusPolicy(QWidget::NoFocus);
00227 mBtnBcc->setFocusPolicy(QWidget::NoFocus);
00228
00229
00230 connect(mBtnTo,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
00231 connect(mBtnCc,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
00232 connect(mBtnBcc,SIGNAL(clicked()),SLOT(slotAddrBookTo()));
00233
00234
00235 connect(mEdtTo,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00236 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00237 connect(mEdtCc,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00238 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00239 connect(mEdtBcc,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00240 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00241
00242 mEdtTo->setFocus();
00243 } else {
00244 mEdtTo = 0;
00245 mEdtCc = 0;
00246 mEdtBcc = 0;
00247
00248 mLblTo = 0;
00249 mLblCc = 0;
00250 mLblBcc = 0;
00251
00252 mBtnTo = 0;
00253 mBtnCc = 0;
00254 mBtnBcc = 0;
00255
00256
00257 mRecipientsEditor = new RecipientsEditor( mMainWidget );
00258
00259 mRecipientsEditor->setFocus();
00260 }
00261 mEdtSubject = new KMLineEditSpell(false,mMainWidget, "subjectLine");
00262 mLblIdentity = new QLabel(mMainWidget);
00263 mDictionaryLabel = new QLabel( mMainWidget );
00264 mLblFcc = new QLabel(mMainWidget);
00265 mLblTransport = new QLabel(mMainWidget);
00266 mLblFrom = new QLabel(mMainWidget);
00267 mLblSubject = new QLabel(mMainWidget);
00268 QString sticky = i18n("Sticky");
00269 mBtnIdentity = new QCheckBox(sticky,mMainWidget);
00270 mBtnFcc = new QCheckBox(sticky,mMainWidget);
00271 mBtnTransport = new QCheckBox(sticky,mMainWidget);
00272
00273
00274 mHtmlMarkup = GlobalSettings::self()->useHtmlMarkup();
00275 mShowHeaders = GlobalSettings::self()->headers();
00276 mDone = false;
00277 mGrid = 0;
00278 mAtmListView = 0;
00279 mAtmList.setAutoDelete(TRUE);
00280 mAtmTempList.setAutoDelete(TRUE);
00281 mAtmModified = FALSE;
00282 mAutoDeleteMsg = FALSE;
00283 mFolder = 0;
00284 mAutoCharset = TRUE;
00285 mFixedFontAction = 0;
00286 mTempDir = 0;
00287 mSplitter = new QSplitter( Qt::Vertical, mMainWidget, "mSplitter" );
00288 mEditor = new KMEdit( mSplitter, this, mDictionaryCombo->spellConfig() );
00289 mSplitter->moveToFirst( mEditor );
00290 mSplitter->setOpaqueResize( true );
00291
00292 mEditor->initializeAutoSpellChecking();
00293 mEditor->setTextFormat(Qt::PlainText);
00294 mEditor->setAcceptDrops( true );
00295
00296 QWhatsThis::add( mBtnIdentity,
00297 GlobalSettings::self()->stickyIdentityItem()->whatsThis() );
00298 QWhatsThis::add( mBtnFcc,
00299 GlobalSettings::self()->stickyFccItem()->whatsThis() );
00300 QWhatsThis::add( mBtnTransport,
00301 GlobalSettings::self()->stickyTransportItem()->whatsThis() );
00302
00303 mSpellCheckInProgress=FALSE;
00304
00305 setCaption( i18n("Composer") );
00306 setMinimumSize(200,200);
00307
00308 mBtnIdentity->setFocusPolicy(QWidget::NoFocus);
00309 mBtnFcc->setFocusPolicy(QWidget::NoFocus);
00310 mBtnTransport->setFocusPolicy(QWidget::NoFocus);
00311
00312 mAtmListView = new AttachmentListView( this, mSplitter,
00313 "attachment list view" );
00314 mAtmListView->setSelectionMode( QListView::Extended );
00315 mAtmListView->addColumn( i18n("Name"), 200 );
00316 mAtmListView->addColumn( i18n("Size"), 80 );
00317 mAtmListView->addColumn( i18n("Encoding"), 120 );
00318 int atmColType = mAtmListView->addColumn( i18n("Type"), 120 );
00319
00320 mAtmListView->header()->setStretchEnabled( true, atmColType );
00321 mAtmEncryptColWidth = 80;
00322 mAtmSignColWidth = 80;
00323 mAtmCompressColWidth = 100;
00324 mAtmColCompress = mAtmListView->addColumn( i18n("Compress"),
00325 mAtmCompressColWidth );
00326 mAtmColEncrypt = mAtmListView->addColumn( i18n("Encrypt"),
00327 mAtmEncryptColWidth );
00328 mAtmColSign = mAtmListView->addColumn( i18n("Sign"),
00329 mAtmSignColWidth );
00330 mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
00331 mAtmListView->setColumnWidth( mAtmColSign, 0 );
00332 mAtmListView->setAllColumnsShowFocus( true );
00333
00334 connect( mAtmListView,
00335 SIGNAL( doubleClicked( QListViewItem* ) ),
00336 SLOT( slotAttachOpen() ) );
00337 connect( mAtmListView,
00338 SIGNAL( rightButtonPressed( QListViewItem*, const QPoint&, int ) ),
00339 SLOT( slotAttachPopupMenu( QListViewItem*, const QPoint&, int ) ) );
00340 connect( mAtmListView,
00341 SIGNAL( selectionChanged() ),
00342 SLOT( slotUpdateAttachActions() ) );
00343 connect( mAtmListView,
00344 SIGNAL( attachmentDeleted() ),
00345 SLOT( slotAttachRemove() ) );
00346 mAttachMenu = 0;
00347
00348 readConfig();
00349 setupStatusBar();
00350 setupActions();
00351 setupEditor();
00352
00353 applyMainWindowSettings(KMKernel::config(), "Composer");
00354
00355 connect( mEdtSubject, SIGNAL( subjectTextSpellChecked() ),
00356 SLOT( slotSubjectTextSpellChecked() ) );
00357 connect(mEdtSubject,SIGNAL(textChanged(const QString&)),
00358 SLOT(slotUpdWinTitle(const QString&)));
00359 connect(mIdentity,SIGNAL(identityChanged(uint)),
00360 SLOT(slotIdentityChanged(uint)));
00361 connect( kmkernel->identityManager(), SIGNAL(changed(uint)),
00362 SLOT(slotIdentityChanged(uint)));
00363
00364 connect(mEdtFrom,SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
00365 SLOT(slotCompletionModeChanged(KGlobalSettings::Completion)));
00366 connect(kmkernel->folderMgr(),SIGNAL(folderRemoved(KMFolder*)),
00367 SLOT(slotFolderRemoved(KMFolder*)));
00368 connect(kmkernel->imapFolderMgr(),SIGNAL(folderRemoved(KMFolder*)),
00369 SLOT(slotFolderRemoved(KMFolder*)));
00370 connect(kmkernel->dimapFolderMgr(),SIGNAL(folderRemoved(KMFolder*)),
00371 SLOT(slotFolderRemoved(KMFolder*)));
00372 connect( kmkernel, SIGNAL( configChanged() ),
00373 this, SLOT( slotConfigChanged() ) );
00374
00375 connect (mEditor, SIGNAL (spellcheck_done(int)),
00376 this, SLOT (slotSpellcheckDone (int)));
00377 connect (mEditor, SIGNAL( pasteImage() ),
00378 this, SLOT (slotPaste() ) );
00379 connect (mEditor, SIGNAL( focusChanged(bool) ),
00380 this, SLOT (editorFocusChanged(bool)) );
00381
00382 mMainWidget->resize(480,510);
00383 setCentralWidget(mMainWidget);
00384 rethinkFields();
00385
00386 if ( !mClassicalRecipients ) {
00387
00388
00389 rethinkFields();
00390 }
00391
00392 if ( GlobalSettings::self()->useExternalEditor() ) {
00393 mEditor->setUseExternalEditor(true);
00394 mEditor->setExternalEditorPath( GlobalSettings::self()->externalEditor() );
00395 }
00396
00397 initAutoSave();
00398
00399 mMsg = 0;
00400 if (aMsg)
00401 setMsg(aMsg);
00402 fontChanged( mEditor->currentFont() );
00403
00404 mDone = true;
00405 }
00406
00407
00408 KMComposeWin::~KMComposeWin()
00409 {
00410 writeConfig();
00411 if (mFolder && mMsg)
00412 {
00413 mAutoDeleteMsg = FALSE;
00414 mFolder->addMsg(mMsg);
00415
00416 mFolder->unGetMsg( mFolder->count() - 1 );
00417 }
00418 if (mAutoDeleteMsg) {
00419 delete mMsg;
00420 mMsg = 0;
00421 }
00422 QMap<KIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.begin();
00423 while ( it != mMapAtmLoadData.end() )
00424 {
00425 KIO::Job *job = it.key();
00426 mMapAtmLoadData.remove( it );
00427 job->kill();
00428 it = mMapAtmLoadData.begin();
00429 }
00430 deleteAll( mComposedMessages );
00431 }
00432
00433 void KMComposeWin::setAutoDeleteWindow( bool f )
00434 {
00435 if ( f )
00436 setWFlags( getWFlags() | WDestructiveClose );
00437 else
00438 setWFlags( getWFlags() & ~WDestructiveClose );
00439 }
00440
00441
00442 void KMComposeWin::send(int how)
00443 {
00444 switch (how) {
00445 case 1:
00446 slotSendNow();
00447 break;
00448 default:
00449 case 0:
00450
00451 case 2:
00452 slotSendLater();
00453 break;
00454 }
00455 }
00456
00457
00458 void KMComposeWin::addAttachment(KURL url,QString )
00459 {
00460 addAttach(url);
00461 }
00462
00463
00464 void KMComposeWin::addAttachment(const QString &name,
00465 const QCString &,
00466 const QByteArray &data,
00467 const QCString &type,
00468 const QCString &subType,
00469 const QCString ¶mAttr,
00470 const QString ¶mValue,
00471 const QCString &contDisp)
00472 {
00473 if (!data.isEmpty()) {
00474 KMMessagePart *msgPart = new KMMessagePart;
00475 msgPart->setName(name);
00476 QValueList<int> dummy;
00477 msgPart->setBodyAndGuessCte(data, dummy,
00478 kmkernel->msgSender()->sendQuotedPrintable());
00479 msgPart->setTypeStr(type);
00480 msgPart->setSubtypeStr(subType);
00481 msgPart->setParameter(paramAttr,paramValue);
00482 msgPart->setContentDisposition(contDisp);
00483 addAttach(msgPart);
00484 }
00485 }
00486
00487 void KMComposeWin::addImageFromClipboard()
00488 {
00489 bool ok;
00490 QFile *tmpFile;
00491
00492 QString attName = KInputDialog::getText( "KMail", i18n("Name of the attachment:"), QString::null, &ok, this );
00493 if ( !ok )
00494 return;
00495
00496 mTempDir = new KTempDir();
00497 mTempDir->setAutoDelete( true );
00498
00499 if ( attName.lower().endsWith(".png") )
00500 tmpFile = new QFile(mTempDir->name() + attName );
00501 else
00502 tmpFile = new QFile(mTempDir->name() + attName + ".png" );
00503
00504 if ( !QApplication::clipboard()->image().save( tmpFile->name(), "PNG" ) ) {
00505 KMessageBox::error( this, i18n("Unknown error trying to save image."), i18n("Attaching Image Failed") );
00506 delete mTempDir;
00507 mTempDir = 0;
00508 return;
00509 }
00510
00511 addAttach( tmpFile->name() );
00512 }
00513
00514 void KMComposeWin::setBody(QString body)
00515 {
00516 mEditor->setText(body);
00517 }
00518
00519
00520 bool KMComposeWin::event(QEvent *e)
00521 {
00522 if (e->type() == QEvent::ApplicationPaletteChange)
00523 {
00524 readColorConfig();
00525 }
00526 return KMail::Composer::event(e);
00527 }
00528
00529
00530
00531 void KMComposeWin::readColorConfig(void)
00532 {
00533 if ( GlobalSettings::self()->useDefaultColors() ) {
00534 mForeColor = QColor(kapp->palette().active().text());
00535 mBackColor = QColor(kapp->palette().active().base());
00536 } else {
00537 mForeColor = GlobalSettings::self()->foregroundColor();
00538 mBackColor = GlobalSettings::self()->backgroundColor();
00539 }
00540
00541
00542 mPalette = kapp->palette();
00543 QColorGroup cgrp = mPalette.active();
00544 cgrp.setColor( QColorGroup::Base, mBackColor);
00545 cgrp.setColor( QColorGroup::Text, mForeColor);
00546 mPalette.setDisabled(cgrp);
00547 mPalette.setActive(cgrp);
00548 mPalette.setInactive(cgrp);
00549
00550 mEdtFrom->setPalette(mPalette);
00551 mEdtReplyTo->setPalette(mPalette);
00552 if ( mClassicalRecipients ) {
00553 mEdtTo->setPalette(mPalette);
00554 mEdtCc->setPalette(mPalette);
00555 mEdtBcc->setPalette(mPalette);
00556 }
00557 mEdtSubject->setPalette(mPalette);
00558 mTransport->setPalette(mPalette);
00559 mEditor->setPalette(mPalette);
00560 mFcc->setPalette(mPalette);
00561 }
00562
00563
00564 void KMComposeWin::readConfig(void)
00565 {
00566 mDefCharset = KMMessage::defaultCharset();
00567 mBtnIdentity->setChecked( GlobalSettings::self()->stickyIdentity() );
00568 if (mBtnIdentity->isChecked()) {
00569 mId = (GlobalSettings::self()->previousIdentity()!=0) ?
00570 GlobalSettings::self()->previousIdentity() : mId;
00571 }
00572 mBtnFcc->setChecked( GlobalSettings::self()->stickyFcc() );
00573 mBtnTransport->setChecked( GlobalSettings::self()->stickyTransport() );
00574 QStringList transportHistory = GlobalSettings::self()->transportHistory();
00575 QString currentTransport = GlobalSettings::self()->currentTransport();
00576
00577 mEdtFrom->setCompletionMode( (KGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
00578 mEdtReplyTo->setCompletionMode( (KGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
00579 if ( mClassicalRecipients ) {
00580 mEdtTo->setCompletionMode( (KGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
00581 mEdtCc->setCompletionMode( (KGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
00582 mEdtBcc->setCompletionMode( (KGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
00583 }
00584
00585 readColorConfig();
00586
00587 if ( GlobalSettings::self()->useDefaultFonts() ) {
00588 mBodyFont = KGlobalSettings::generalFont();
00589 mFixedFont = KGlobalSettings::fixedFont();
00590 } else {
00591 mBodyFont = GlobalSettings::self()->composerFont();
00592 mFixedFont = GlobalSettings::self()->fixedFont();
00593 }
00594
00595 slotUpdateFont();
00596 mEdtFrom->setFont(mBodyFont);
00597 mEdtReplyTo->setFont(mBodyFont);
00598 if ( mClassicalRecipients ) {
00599 mEdtTo->setFont(mBodyFont);
00600 mEdtCc->setFont(mBodyFont);
00601 mEdtBcc->setFont(mBodyFont);
00602 }
00603 mEdtSubject->setFont(mBodyFont);
00604
00605 QSize siz = GlobalSettings::self()->composerSize();
00606 if (siz.width() < 200) siz.setWidth(200);
00607 if (siz.height() < 200) siz.setHeight(200);
00608 resize(siz);
00609
00610 mIdentity->setCurrentIdentity( mId );
00611
00612 kdDebug(5006) << "KMComposeWin::readConfig. " << mIdentity->currentIdentityName() << endl;
00613 const KPIM::Identity & ident =
00614 kmkernel->identityManager()->identityForUoid( mIdentity->currentIdentity() );
00615
00616 mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
00617
00618 mTransport->clear();
00619 mTransport->insertStringList( KMTransportInfo::availableTransports() );
00620 while ( transportHistory.count() > (uint)GlobalSettings::self()->maxTransportEntries() )
00621 transportHistory.remove( transportHistory.last() );
00622 mTransport->insertStringList( transportHistory );
00623 mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
00624 if ( mBtnTransport->isChecked() ) {
00625 setTransport( currentTransport );
00626 }
00627
00628 QString fccName = "";
00629 if ( mBtnFcc->isChecked() ) {
00630 fccName = GlobalSettings::self()->previousFcc();
00631 } else if ( !ident.fcc().isEmpty() ) {
00632 fccName = ident.fcc();
00633 }
00634
00635 setFcc( fccName );
00636 }
00637
00638
00639 void KMComposeWin::writeConfig(void)
00640 {
00641 GlobalSettings::self()->setHeaders( mShowHeaders );
00642 GlobalSettings::self()->setStickyTransport( mBtnTransport->isChecked() );
00643 GlobalSettings::self()->setStickyIdentity( mBtnIdentity->isChecked() );
00644 GlobalSettings::self()->setStickyFcc( mBtnFcc->isChecked() );
00645 GlobalSettings::self()->setPreviousIdentity( mIdentity->currentIdentity() );
00646 GlobalSettings::self()->setCurrentTransport( mTransport->currentText() );
00647 GlobalSettings::self()->setPreviousFcc( mFcc->getFolder()->idString() );
00648 GlobalSettings::self()->setAutoSpellChecking(
00649 mAutoSpellCheckingAction->isChecked() );
00650 QStringList transportHistory = GlobalSettings::self()->transportHistory();
00651 transportHistory.remove(mTransport->currentText());
00652 if (KMTransportInfo::availableTransports().findIndex(mTransport
00653 ->currentText()) == -1) {
00654 transportHistory.prepend(mTransport->currentText());
00655 }
00656 GlobalSettings::self()->setTransportHistory( transportHistory );
00657 GlobalSettings::self()->setUseFixedFont( mFixedFontAction->isChecked() );
00658 GlobalSettings::self()->setUseHtmlMarkup( mHtmlMarkup );
00659 GlobalSettings::self()->setComposerSize( size() );
00660
00661 KConfigGroupSaver saver( KMKernel::config(), "Geometry" );
00662 saveMainWindowSettings( KMKernel::config(), "Composer" );
00663
00664 GlobalSettings::self()->writeConfig();
00665 }
00666
00667
00668 void KMComposeWin::autoSaveMessage()
00669 {
00670 kdDebug(5006) << k_funcinfo << endl;
00671 if ( !mMsg || mComposer || mAutoSaveFilename.isEmpty() )
00672 return;
00673 kdDebug(5006) << k_funcinfo << "autosaving message" << endl;
00674
00675 if ( mAutoSaveTimer )
00676 mAutoSaveTimer->stop();
00677 connect( this, SIGNAL( applyChangesDone( bool ) ),
00678 this, SLOT( slotContinueAutoSave( bool ) ) );
00679
00680
00681
00682 applyChanges( true, true );
00683
00684
00685 qApp->enter_loop();
00686
00687
00688 if ( mComposedMessages.isEmpty() ) {
00689 kdDebug(5006) << "Composing the message failed." << endl;
00690 return;
00691 }
00692 KMMessage *msg = mComposedMessages.first();
00693
00694 kdDebug(5006) << k_funcinfo << "opening autoSaveFile " << mAutoSaveFilename
00695 << endl;
00696 const QString filename =
00697 KMKernel::localDataPath() + "autosave/cur/" + mAutoSaveFilename;
00698 KSaveFile autoSaveFile( filename, 0600 );
00699 int status = autoSaveFile.status();
00700 kdDebug(5006) << k_funcinfo << "autoSaveFile.status() = " << status << endl;
00701 if ( status == 0 ) {
00702 kdDebug(5006) << "autosaving message in " << filename << endl;
00703 int fd = autoSaveFile.handle();
00704 QCString msgStr = msg->asString();
00705 if ( ::write( fd, msgStr, msgStr.length() ) == -1 )
00706 status = errno;
00707 }
00708 if ( status == 0 ) {
00709 kdDebug(5006) << k_funcinfo << "closing autoSaveFile" << endl;
00710 autoSaveFile.close();
00711 mLastAutoSaveErrno = 0;
00712 }
00713 else {
00714 kdDebug(5006) << k_funcinfo << "autosaving failed" << endl;
00715 autoSaveFile.abort();
00716 if ( status != mLastAutoSaveErrno ) {
00717
00718 KMessageBox::queuedMessageBox( 0, KMessageBox::Sorry,
00719 i18n("Autosaving the message as %1 "
00720 "failed.\n"
00721 "Reason: %2" )
00722 .arg( filename, strerror( status ) ),
00723 i18n("Autosaving Failed") );
00724 mLastAutoSaveErrno = status;
00725 }
00726 }
00727
00728 if ( autoSaveInterval() > 0 )
00729 mAutoSaveTimer->start( autoSaveInterval() );
00730 }
00731
00732 void KMComposeWin::slotContinueAutoSave( bool )
00733 {
00734 disconnect( this, SIGNAL( applyChangesDone( bool ) ),
00735 this, SLOT( slotContinueAutoSave( bool ) ) );
00736 qApp->exit_loop();
00737 }
00738
00739
00740 void KMComposeWin::slotView(void)
00741 {
00742 if (!mDone)
00743 return;
00744
00745 int id;
00746
00747
00748
00749 if (!sender()->isA("KToggleAction"))
00750 return;
00751 KToggleAction *act = (KToggleAction *) sender();
00752
00753 if (act == mAllFieldsAction)
00754 id = 0;
00755 else if (act == mIdentityAction)
00756 id = HDR_IDENTITY;
00757 else if (act == mTransportAction)
00758 id = HDR_TRANSPORT;
00759 else if (act == mFromAction)
00760 id = HDR_FROM;
00761 else if (act == mReplyToAction)
00762 id = HDR_REPLY_TO;
00763 else if (act == mToAction)
00764 id = HDR_TO;
00765 else if (act == mCcAction)
00766 id = HDR_CC;
00767 else if (act == mBccAction)
00768 id = HDR_BCC;
00769 else if (act == mSubjectAction)
00770 id = HDR_SUBJECT;
00771 else if (act == mFccAction)
00772 id = HDR_FCC;
00773 else if ( act == mDictionaryAction )
00774 id = HDR_DICTIONARY;
00775 else
00776 {
00777 id = 0;
00778 kdDebug(5006) << "Something is wrong (Oh, yeah?)" << endl;
00779 return;
00780 }
00781
00782
00783
00784
00785 if (!act->isChecked())
00786 {
00787
00788 if (id > 0) mShowHeaders = mShowHeaders & ~id;
00789 else mShowHeaders = abs(mShowHeaders);
00790 }
00791 else
00792 {
00793
00794 if (id > 0) mShowHeaders |= id;
00795 else mShowHeaders = -abs(mShowHeaders);
00796 }
00797 rethinkFields(true);
00798 }
00799
00800 int KMComposeWin::calcColumnWidth(int which, long allShowing, int width)
00801 {
00802 if ( (allShowing & which) == 0 )
00803 return width;
00804
00805 QLabel *w;
00806 if ( which == HDR_IDENTITY )
00807 w = mLblIdentity;
00808 else if ( which == HDR_DICTIONARY )
00809 w = mDictionaryLabel;
00810 else if ( which == HDR_FCC )
00811 w = mLblFcc;
00812 else if ( which == HDR_TRANSPORT )
00813 w = mLblTransport;
00814 else if ( which == HDR_FROM )
00815 w = mLblFrom;
00816 else if ( which == HDR_REPLY_TO )
00817 w = mLblReplyTo;
00818 else if ( which == HDR_SUBJECT )
00819 w = mLblSubject;
00820 else
00821 return width;
00822
00823 w->setBuddy( mEditor );
00824 w->adjustSize();
00825 w->show();
00826 return QMAX( width, w->sizeHint().width() );
00827 }
00828
00829 void KMComposeWin::rethinkFields(bool fromSlot)
00830 {
00831
00832 int mask, row, numRows;
00833 long showHeaders;
00834
00835 if (mShowHeaders < 0)
00836 showHeaders = HDR_ALL;
00837 else
00838 showHeaders = mShowHeaders;
00839
00840 for (mask=1,mNumHeaders=0; mask<=showHeaders; mask<<=1)
00841 if ((showHeaders&mask) != 0) mNumHeaders++;
00842
00843 numRows = mNumHeaders + 1;
00844
00845 delete mGrid;
00846 mGrid = new QGridLayout(mMainWidget, numRows, 3, KDialogBase::marginHint()/2, KDialogBase::spacingHint());
00847 mGrid->setColStretch(0, 1);
00848 mGrid->setColStretch(1, 100);
00849 mGrid->setColStretch(2, 1);
00850 mGrid->setRowStretch(mNumHeaders, 100);
00851
00852 row = 0;
00853 kdDebug(5006) << "KMComposeWin::rethinkFields" << endl;
00854 if (mRecipientsEditor)
00855 mLabelWidth = mRecipientsEditor->setFirstColumnWidth( 0 );
00856 mLabelWidth = calcColumnWidth( HDR_IDENTITY, showHeaders, mLabelWidth );
00857 mLabelWidth = calcColumnWidth( HDR_DICTIONARY, showHeaders, mLabelWidth );
00858 mLabelWidth = calcColumnWidth( HDR_FCC, showHeaders, mLabelWidth );
00859 mLabelWidth = calcColumnWidth( HDR_TRANSPORT, showHeaders, mLabelWidth );
00860 mLabelWidth = calcColumnWidth( HDR_FROM, showHeaders, mLabelWidth );
00861 mLabelWidth = calcColumnWidth( HDR_REPLY_TO, showHeaders, mLabelWidth );
00862 mLabelWidth = calcColumnWidth( HDR_SUBJECT, showHeaders, mLabelWidth );
00863
00864 if (!fromSlot) mAllFieldsAction->setChecked(showHeaders==HDR_ALL);
00865
00866 if (!fromSlot) mIdentityAction->setChecked(abs(mShowHeaders)&HDR_IDENTITY);
00867 rethinkHeaderLine(showHeaders,HDR_IDENTITY, row, i18n("&Identity:"),
00868 mLblIdentity, mIdentity, mBtnIdentity);
00869
00870 if (!fromSlot) mDictionaryAction->setChecked(abs(mShowHeaders)&HDR_DICTIONARY);
00871 rethinkHeaderLine(showHeaders,HDR_DICTIONARY, row, i18n("&Dictionary:"),
00872 mDictionaryLabel, mDictionaryCombo, 0 );
00873
00874 if (!fromSlot) mFccAction->setChecked(abs(mShowHeaders)&HDR_FCC);
00875 rethinkHeaderLine(showHeaders,HDR_FCC, row, i18n("&Sent-Mail folder:"),
00876 mLblFcc, mFcc, mBtnFcc);
00877
00878 if (!fromSlot) mTransportAction->setChecked(abs(mShowHeaders)&HDR_TRANSPORT);
00879 rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row, i18n("&Mail transport:"),
00880 mLblTransport, mTransport, mBtnTransport);
00881
00882 if (!fromSlot) mFromAction->setChecked(abs(mShowHeaders)&HDR_FROM);
00883 rethinkHeaderLine(showHeaders,HDR_FROM, row, i18n("sender address field", "&From:"),
00884 mLblFrom, mEdtFrom );
00885
00886 QWidget *prevFocus = mEdtFrom;
00887
00888 if (!fromSlot) mReplyToAction->setChecked(abs(mShowHeaders)&HDR_REPLY_TO);
00889 rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,i18n("&Reply to:"),
00890 mLblReplyTo, mEdtReplyTo, mBtnReplyTo);
00891 if ( showHeaders & HDR_REPLY_TO ) {
00892 prevFocus = connectFocusMoving( prevFocus, mEdtReplyTo );
00893 }
00894
00895 if ( mClassicalRecipients ) {
00896 if (!fromSlot) mToAction->setChecked(abs(mShowHeaders)&HDR_TO);
00897 rethinkHeaderLine(showHeaders, HDR_TO, row, i18n("recipient address field", "&To:"),
00898 mLblTo, mEdtTo, mBtnTo,
00899 i18n("Primary Recipients"),
00900 i18n("<qt>The email addresses you put "
00901 "in this field receive a copy of the email.</qt>"));
00902 if ( showHeaders & HDR_TO ) {
00903 prevFocus = connectFocusMoving( prevFocus, mEdtTo );
00904 }
00905
00906 if (!fromSlot) mCcAction->setChecked(abs(mShowHeaders)&HDR_CC);
00907 rethinkHeaderLine(showHeaders, HDR_CC, row, i18n("&Copy to (CC):"),
00908 mLblCc, mEdtCc, mBtnCc,
00909 i18n("Additional Recipients"),
00910 i18n("<qt>The email addresses you put "
00911 "in this field receive a copy of the email. "
00912 "Technically it is the same thing as putting all the "
00913 "addresses in the <b>To:</b> field but differs in "
00914 "that it usually symbolises the receiver of the "
00915 "Carbon Copy (CC) is a listener, not the main "
00916 "recipient.</qt>"));
00917 if ( showHeaders & HDR_CC ) {
00918 prevFocus = connectFocusMoving( prevFocus, mEdtCc );
00919 }
00920
00921 if (!fromSlot) mBccAction->setChecked(abs(mShowHeaders)&HDR_BCC);
00922 rethinkHeaderLine(showHeaders,HDR_BCC, row, i18n("&Blind copy to (BCC):"),
00923 mLblBcc, mEdtBcc, mBtnBcc,
00924 i18n("Hidden Recipients"),
00925 i18n("<qt>Essentially the same thing "
00926 "as the <b>Copy To:</b> field but differs in that "
00927 "all other recipients do not see who receives a "
00928 "blind copy.</qt>"));
00929 if ( showHeaders & HDR_BCC ) {
00930 prevFocus = connectFocusMoving( prevFocus, mEdtBcc );
00931 }
00932 } else {
00933 mGrid->addMultiCellWidget( mRecipientsEditor, row, row, 0, 2 );
00934 ++row;
00935
00936 if ( showHeaders & HDR_REPLY_TO ) {
00937 connect( mEdtReplyTo, SIGNAL( focusDown() ), mRecipientsEditor,
00938 SLOT( setFocusTop() ) );
00939 } else {
00940 connect( mEdtFrom, SIGNAL( focusDown() ), mRecipientsEditor,
00941 SLOT( setFocusTop() ) );
00942 }
00943 if ( showHeaders & HDR_REPLY_TO ) {
00944 connect( mRecipientsEditor, SIGNAL( focusUp() ), mEdtReplyTo, SLOT( setFocus() ) );
00945 } else {
00946 connect( mRecipientsEditor, SIGNAL( focusUp() ), mEdtFrom, SLOT( setFocus() ) );
00947 }
00948
00949 connect( mRecipientsEditor, SIGNAL( focusDown() ), mEdtSubject,
00950 SLOT( setFocus() ) );
00951 connect( mEdtSubject, SIGNAL( focusUp() ), mRecipientsEditor,
00952 SLOT( setFocusBottom() ) );
00953
00954 prevFocus = mRecipientsEditor;
00955 }
00956 if (!fromSlot) mSubjectAction->setChecked(abs(mShowHeaders)&HDR_SUBJECT);
00957 rethinkHeaderLine(showHeaders,HDR_SUBJECT, row, i18n("S&ubject:"),
00958 mLblSubject, mEdtSubject);
00959 connectFocusMoving( mEdtSubject, mEditor );
00960
00961 assert(row<=mNumHeaders);
00962
00963 mGrid->addMultiCellWidget(mSplitter, row, mNumHeaders, 0, 2);
00964
00965 if( !mAtmList.isEmpty() )
00966 mAtmListView->show();
00967 else
00968 mAtmListView->hide();
00969 resize(this->size());
00970 repaint();
00971
00972 mGrid->activate();
00973
00974 slotUpdateAttachActions();
00975 mIdentityAction->setEnabled(!mAllFieldsAction->isChecked());
00976 mDictionaryAction->setEnabled( !mAllFieldsAction->isChecked() );
00977 mTransportAction->setEnabled(!mAllFieldsAction->isChecked());
00978 mFromAction->setEnabled(!mAllFieldsAction->isChecked());
00979 if ( mReplyToAction ) mReplyToAction->setEnabled(!mAllFieldsAction->isChecked());
00980 if ( mToAction ) mToAction->setEnabled(!mAllFieldsAction->isChecked());
00981 if ( mCcAction ) mCcAction->setEnabled(!mAllFieldsAction->isChecked());
00982 if ( mBccAction ) mBccAction->setEnabled(!mAllFieldsAction->isChecked());
00983 mFccAction->setEnabled(!mAllFieldsAction->isChecked());
00984 mSubjectAction->setEnabled(!mAllFieldsAction->isChecked());
00985 if (mRecipientsEditor)
00986 mRecipientsEditor->setFirstColumnWidth( mLabelWidth );
00987 }
00988
00989 QWidget *KMComposeWin::connectFocusMoving( QWidget *prev, QWidget *next )
00990 {
00991 connect( prev, SIGNAL( focusDown() ), next, SLOT( setFocus() ) );
00992 connect( next, SIGNAL( focusUp() ), prev, SLOT( setFocus() ) );
00993
00994 return next;
00995 }
00996
00997
00998 void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
00999 const QString &aLabelStr, QLabel* aLbl,
01000 QLineEdit* aEdt, QPushButton* aBtn,
01001 const QString &toolTip, const QString &whatsThis )
01002 {
01003 if (aValue & aMask)
01004 {
01005 aLbl->setText(aLabelStr);
01006 if ( !toolTip.isEmpty() )
01007 QToolTip::add( aLbl, toolTip );
01008 if ( !whatsThis.isEmpty() )
01009 QWhatsThis::add( aLbl, whatsThis );
01010 aLbl->setFixedWidth( mLabelWidth );
01011 aLbl->setBuddy(aEdt);
01012 mGrid->addWidget(aLbl, aRow, 0);
01013 aEdt->setBackgroundColor( mBackColor );
01014 aEdt->show();
01015
01016 if (aBtn) {
01017 mGrid->addWidget(aEdt, aRow, 1);
01018
01019 mGrid->addWidget(aBtn, aRow, 2);
01020 aBtn->show();
01021 } else {
01022 mGrid->addMultiCellWidget(aEdt, aRow, aRow, 1, 2 );
01023 }
01024 aRow++;
01025 }
01026 else
01027 {
01028 aLbl->hide();
01029 aEdt->hide();
01030 if (aBtn) aBtn->hide();
01031 }
01032 }
01033
01034
01035 void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
01036 const QString &aLabelStr, QLabel* aLbl,
01037 QComboBox* aCbx, QCheckBox* aChk)
01038 {
01039 if (aValue & aMask)
01040 {
01041 aLbl->setText(aLabelStr);
01042 aLbl->adjustSize();
01043 aLbl->resize((int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
01044 aLbl->setMinimumSize(aLbl->size());
01045 aLbl->show();
01046 aLbl->setBuddy(aCbx);
01047 mGrid->addWidget(aLbl, aRow, 0);
01048 aCbx->show();
01049 aCbx->setMinimumSize(100, aLbl->height()+2);
01050
01051 mGrid->addWidget(aCbx, aRow, 1);
01052 if ( aChk ) {
01053 mGrid->addWidget(aChk, aRow, 2);
01054 aChk->setFixedSize(aChk->sizeHint().width(), aLbl->height());
01055 aChk->show();
01056 }
01057 aRow++;
01058 }
01059 else
01060 {
01061 aLbl->hide();
01062 aCbx->hide();
01063 if ( aChk )
01064 aChk->hide();
01065 }
01066 }
01067
01068
01069 void KMComposeWin::getTransportMenu()
01070 {
01071 QStringList availTransports;
01072
01073 mActNowMenu->clear();
01074 mActLaterMenu->clear();
01075 availTransports = KMail::TransportManager::transportNames();
01076 QStringList::Iterator it;
01077 int id = 0;
01078 for(it = availTransports.begin(); it != availTransports.end() ; ++it, id++)
01079 {
01080 mActNowMenu->insertItem((*it).replace("&", "&&"), id);
01081 mActLaterMenu->insertItem((*it).replace("&", "&&"), id);
01082 }
01083 }
01084
01085
01086
01087 void KMComposeWin::setupActions(void)
01088 {
01089 KActionMenu *actActionNowMenu, *actActionLaterMenu;
01090
01091 if (kmkernel->msgSender()->sendImmediate())
01092 {
01093
01094 ( void ) new KAction( i18n("&Send Mail"), "mail_send", CTRL+Key_Return,
01095 this, SLOT(slotSendNow()), actionCollection(),"send_default");
01096
01097
01098 actActionNowMenu = new KActionMenu (i18n("&Send Mail Via"), "mail_send",
01099 actionCollection(), "send_default_via" );
01100
01101 (void) new KAction (i18n("Send &Later"), "queue", 0, this,
01102 SLOT(slotSendLater()), actionCollection(),"send_alternative");
01103 actActionLaterMenu = new KActionMenu (i18n("Send &Later Via"), "queue",
01104 actionCollection(), "send_alternative_via" );
01105
01106 }
01107 else
01108 {
01109
01110 (void) new KAction (i18n("Send &Later"), "queue",
01111 CTRL+Key_Return,
01112 this, SLOT(slotSendLater()), actionCollection(),"send_default");
01113 actActionLaterMenu = new KActionMenu (i18n("Send &Later Via"), "queue",
01114 actionCollection(), "send_default_via" );
01115
01116 ( void ) new KAction( i18n("&Send Mail"), "mail_send", 0,
01117 this, SLOT(slotSendNow()), actionCollection(),"send_alternative");
01118
01119
01120 actActionNowMenu = new KActionMenu (i18n("&Send Mail Via"), "mail_send",
01121 actionCollection(), "send_alternative_via" );
01122
01123 }
01124
01125
01126 actActionNowMenu->setDelayed(true);
01127 actActionLaterMenu->setDelayed(true);
01128
01129 connect( actActionNowMenu, SIGNAL( activated() ), this,
01130 SLOT( slotSendNow() ) );
01131 connect( actActionLaterMenu, SIGNAL( activated() ), this,
01132 SLOT( slotSendLater() ) );
01133
01134
01135 mActNowMenu = actActionNowMenu->popupMenu();
01136 mActLaterMenu = actActionLaterMenu->popupMenu();
01137
01138 connect( mActNowMenu, SIGNAL( activated( int ) ), this,
01139 SLOT( slotSendNowVia( int ) ) );
01140 connect( mActNowMenu, SIGNAL( aboutToShow() ), this,
01141 SLOT( getTransportMenu() ) );
01142
01143 connect( mActLaterMenu, SIGNAL( activated( int ) ), this,
01144 SLOT( slotSendLaterVia( int ) ) );
01145 connect( mActLaterMenu, SIGNAL( aboutToShow() ), this,
01146 SLOT( getTransportMenu() ) );
01147
01148
01149
01150
01151 (void) new KAction (i18n("Save in &Drafts Folder"), "filesave", 0,
01152 this, SLOT(slotSaveDraft()),
01153 actionCollection(), "save_in_drafts");
01154 (void) new KAction (i18n("&Insert File..."), "fileopen", 0,
01155 this, SLOT(slotInsertFile()),
01156 actionCollection(), "insert_file");
01157 mRecentAction = new KRecentFilesAction (i18n("&Insert File Recent"),
01158 "fileopen", 0,
01159 this, SLOT(slotInsertRecentFile(const KURL&)),
01160 actionCollection(), "insert_file_recent");
01161
01162 mRecentAction->loadEntries( KMKernel::config() );
01163
01164 (void) new KAction (i18n("&Address Book"), "contents",0,
01165 this, SLOT(slotAddrBook()),
01166 actionCollection(), "addressbook");
01167 (void) new KAction (i18n("&New Composer"), "mail_new",
01168 KStdAccel::shortcut(KStdAccel::New),
01169 this, SLOT(slotNewComposer()),
01170 actionCollection(), "new_composer");
01171 (void) new KAction (i18n("New Main &Window"), "window_new", 0,
01172 this, SLOT(slotNewMailReader()),
01173 actionCollection(), "open_mailreader");
01174
01175 if ( !mClassicalRecipients ) {
01176 new KAction( i18n("Select &Recipients..."), CTRL + Key_L, mRecipientsEditor,
01177 SLOT( selectRecipients() ), actionCollection(), "select_recipients" );
01178 new KAction( i18n("Save &Distribution List..."), 0, mRecipientsEditor,
01179 SLOT( saveDistributionList() ), actionCollection(),
01180 "save_distribution_list" );
01181 }
01182
01183
01184 KStdAction::print (this, SLOT(slotPrint()), actionCollection());
01185 KStdAction::close (this, SLOT(slotClose()), actionCollection());
01186
01187 KStdAction::undo (this, SLOT(slotUndo()), actionCollection());
01188 KStdAction::redo (this, SLOT(slotRedo()), actionCollection());
01189 KStdAction::cut (this, SLOT(slotCut()), actionCollection());
01190 KStdAction::copy (this, SLOT(slotCopy()), actionCollection());
01191 KStdAction::pasteText (this, SLOT(slotPaste()), actionCollection());
01192 KStdAction::selectAll (this, SLOT(slotMarkAll()), actionCollection());
01193
01194 KStdAction::find (this, SLOT(slotFind()), actionCollection());
01195 KStdAction::findNext(this, SLOT(slotSearchAgain()), actionCollection());
01196
01197 KStdAction::replace (this, SLOT(slotReplace()), actionCollection());
01198 KStdAction::spelling (this, SLOT(slotSpellcheck()), actionCollection(), "spellcheck");
01199
01200 mPasteQuotation = new KAction (i18n("Pa&ste as Quotation"),0,this,SLOT( slotPasteAsQuotation()),
01201 actionCollection(), "paste_quoted");
01202
01203 (void) new KAction (i18n("Paste as Attac&hment"),0,this,SLOT( slotPasteAsAttachment()),
01204 actionCollection(), "paste_att");
01205
01206 mAddQuoteChars = new KAction(i18n("Add &Quote Characters"), 0, this,
01207 SLOT(slotAddQuotes()), actionCollection(), "tools_quote");
01208
01209 mRemQuoteChars = new KAction(i18n("Re&move Quote Characters"), 0, this,
01210 SLOT(slotRemoveQuotes()), actionCollection(), "tools_unquote");
01211
01212
01213 (void) new KAction (i18n("Cl&ean Spaces"), 0, this, SLOT(slotCleanSpace()),
01214 actionCollection(), "clean_spaces");
01215
01216 mFixedFontAction = new KToggleAction( i18n("Use Fi&xed Font"), 0, this,
01217 SLOT(slotUpdateFont()), actionCollection(), "toggle_fixedfont" );
01218 mFixedFontAction->setChecked( GlobalSettings::self()->useFixedFont() );
01219
01220
01221 mUrgentAction = new KToggleAction (i18n("&Urgent"), 0,
01222 actionCollection(),
01223 "urgent");
01224 mRequestMDNAction = new KToggleAction ( i18n("&Request Disposition Notification"), 0,
01225 actionCollection(),
01226 "options_request_mdn");
01227 mRequestMDNAction->setChecked(GlobalSettings::self()->requestMDN());
01228
01229 mEncodingAction = new KSelectAction( i18n( "Se&t Encoding" ), "charset",
01230 0, this, SLOT(slotSetCharset() ),
01231 actionCollection(), "charsets" );
01232 mWordWrapAction = new KToggleAction (i18n("&Wordwrap"), 0,
01233 actionCollection(), "wordwrap");
01234 mWordWrapAction->setChecked(GlobalSettings::self()->wordWrap());
01235 connect(mWordWrapAction, SIGNAL(toggled(bool)), SLOT(slotWordWrapToggled(bool)));
01236
01237 mAutoSpellCheckingAction =
01238 new KToggleAction( i18n( "&Automatic Spellchecking" ), "spellcheck", 0,
01239 actionCollection(), "options_auto_spellchecking" );
01240 const bool spellChecking = GlobalSettings::self()->autoSpellChecking();
01241 mAutoSpellCheckingAction->setEnabled( !GlobalSettings::self()->useExternalEditor() );
01242 mAutoSpellCheckingAction->setChecked( !GlobalSettings::self()->useExternalEditor() && spellChecking );
01243 slotAutoSpellCheckingToggled( !GlobalSettings::self()->useExternalEditor() && spellChecking );
01244 connect( mAutoSpellCheckingAction, SIGNAL( toggled( bool ) ),
01245 this, SLOT( slotAutoSpellCheckingToggled( bool ) ) );
01246
01247 QStringList encodings = KMMsgBase::supportedEncodings(TRUE);
01248 encodings.prepend( i18n("Auto-Detect"));
01249 mEncodingAction->setItems( encodings );
01250 mEncodingAction->setCurrentItem( -1 );
01251
01252
01253 markupAction = new KToggleAction (i18n("Formatting (HTML)"), 0, this,
01254 SLOT(slotToggleMarkup()),
01255 actionCollection(), "html");
01256
01257 mAllFieldsAction = new KToggleAction (i18n("&All Fields"), 0, this,
01258 SLOT(slotView()),
01259 actionCollection(), "show_all_fields");
01260 mIdentityAction = new KToggleAction (i18n("&Identity"), 0, this,
01261 SLOT(slotView()),
01262 actionCollection(), "show_identity");
01263 mDictionaryAction = new KToggleAction (i18n("&Dictionary"), 0, this,
01264 SLOT(slotView()),
01265 actionCollection(), "show_dictionary");
01266 mFccAction = new KToggleAction (i18n("&Sent-Mail Folder"), 0, this,
01267 SLOT(slotView()),
01268 actionCollection(), "show_fcc");
01269 mTransportAction = new KToggleAction (i18n("&Mail Transport"), 0, this,
01270 SLOT(slotView()),
01271 actionCollection(), "show_transport");
01272 mFromAction = new KToggleAction (i18n("&From"), 0, this,
01273 SLOT(slotView()),
01274 actionCollection(), "show_from");
01275 mReplyToAction = new KToggleAction (i18n("&Reply To"), 0, this,
01276 SLOT(slotView()),
01277 actionCollection(), "show_reply_to");
01278 if ( mClassicalRecipients ) {
01279 mToAction = new KToggleAction (i18n("&To"), 0, this,
01280 SLOT(slotView()),
01281 actionCollection(), "show_to");
01282 mCcAction = new KToggleAction (i18n("&CC"), 0, this,
01283 SLOT(slotView()),
01284 actionCollection(), "show_cc");
01285 mBccAction = new KToggleAction (i18n("&BCC"), 0, this,
01286 SLOT(slotView()),
01287 actionCollection(), "show_bcc");
01288 }
01289 mSubjectAction = new KToggleAction (i18n("S&ubject"), 0, this,
01290 SLOT(slotView()),
01291 actionCollection(), "show_subject");
01292
01293
01294 (void) new KAction (i18n("Append S&ignature"), 0, this,
01295 SLOT(slotAppendSignature()),
01296 actionCollection(), "append_signature");
01297 mAttachPK = new KAction (i18n("Attach &Public Key..."), 0, this,
01298 SLOT(slotInsertPublicKey()),
01299 actionCollection(), "attach_public_key");
01300 mAttachMPK = new KAction (i18n("Attach &My Public Key"), 0, this,
01301 SLOT(slotInsertMyPublicKey()),
01302 actionCollection(), "attach_my_public_key");
01303 (void) new KAction (i18n("&Attach File..."), "attach",
01304 0, this, SLOT(slotAttachFile()),
01305 actionCollection(), "attach");
01306 mAttachRemoveAction = new KAction (i18n("&Remove Attachment"), 0, this,
01307 SLOT(slotAttachRemove()),
01308 actionCollection(), "remove");
01309 mAttachSaveAction = new KAction (i18n("&Save Attachment As..."), "filesave",0,
01310 this, SLOT(slotAttachSave()),
01311 actionCollection(), "attach_save");
01312 mAttachPropertiesAction = new KAction (i18n("Attachment Pr&operties"), 0, this,
01313 SLOT(slotAttachProperties()),
01314 actionCollection(), "attach_properties");
01315
01316 setStandardToolBarMenuEnabled(true);
01317
01318 KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());
01319 KStdAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection());
01320 KStdAction::preferences(kmkernel, SLOT(slotShowConfigurationDialog()), actionCollection());
01321
01322 (void) new KAction (i18n("&Spellchecker..."), 0, this, SLOT(slotSpellcheckConfig()),
01323 actionCollection(), "setup_spellchecker");
01324
01325 if ( Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) ) {
01326 KToggleAction * a = new KToggleAction( i18n( "Encrypt Message with Chiasmus..." ),
01327 "chidecrypted", 0, actionCollection(),
01328 "encrypt_message_chiasmus" );
01329 a->setCheckedState( KGuiItem( i18n( "Encrypt Message with Chiasmus..." ), "chiencrypted" ) );
01330 mEncryptChiasmusAction = a;
01331 connect( mEncryptChiasmusAction, SIGNAL(toggled(bool)),
01332 this, SLOT(slotEncryptChiasmusToggled(bool)) );
01333 } else {
01334 mEncryptChiasmusAction = 0;
01335 }
01336
01337 mEncryptAction = new KToggleAction (i18n("&Encrypt Message"),
01338 "decrypted", 0,
01339 actionCollection(), "encrypt_message");
01340 mSignAction = new KToggleAction (i18n("&Sign Message"),
01341 "signature", 0,
01342 actionCollection(), "sign_message");
01343
01344 const KPIM::Identity & ident =
01345 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
01346
01347
01348 mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
01349 mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
01350
01351 mLastEncryptActionState = false;
01352 mLastSignActionState = GlobalSettings::self()->pgpAutoSign();
01353
01354
01355 mAttachPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() );
01356
01357
01358
01359 mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
01360 !ident.pgpEncryptionKey().isEmpty() );
01361
01362 if ( !Kleo::CryptoBackendFactory::instance()->openpgp() && !Kleo::CryptoBackendFactory::instance()->smime() ) {
01363
01364 mEncryptAction->setEnabled( false );
01365 setEncryption( false );
01366 mSignAction->setEnabled( false );
01367 setSigning( false );
01368 } else {
01369 const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
01370 && !ident.pgpSigningKey().isEmpty();
01371 const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
01372 && !ident.smimeSigningKey().isEmpty();
01373
01374 setEncryption( false );
01375 setSigning( ( canOpenPGPSign || canSMIMESign ) && GlobalSettings::self()->pgpAutoSign() );
01376 }
01377
01378 connect(mEncryptAction, SIGNAL(toggled(bool)),
01379 SLOT(slotEncryptToggled( bool )));
01380 connect(mSignAction, SIGNAL(toggled(bool)),
01381 SLOT(slotSignToggled( bool )));
01382
01383 QStringList l;
01384 for ( int i = 0 ; i < numCryptoMessageFormats ; ++i )
01385 l.push_back( Kleo::cryptoMessageFormatToLabel( cryptoMessageFormats[i] ) );
01386
01387 mCryptoModuleAction = new KSelectAction( i18n( "&Cryptographic Message Format" ), 0,
01388 this, SLOT(slotSelectCryptoModule()),
01389 actionCollection(), "options_select_crypto" );
01390 mCryptoModuleAction->setItems( l );
01391 mCryptoModuleAction->setCurrentItem( format2cb( ident.preferredCryptoMessageFormat() ) );
01392 slotSelectCryptoModule( true );
01393
01394 QStringList styleItems;
01395 styleItems << i18n( "Standard" );
01396 styleItems << i18n( "Bulleted List (Disc)" );
01397 styleItems << i18n( "Bulleted List (Circle)" );
01398 styleItems << i18n( "Bulleted List (Square)" );
01399 styleItems << i18n( "Ordered List (Decimal)" );
01400 styleItems << i18n( "Ordered List (Alpha lower)" );
01401 styleItems << i18n( "Ordered List (Alpha upper)" );
01402
01403 listAction = new KSelectAction( i18n( "Select Style" ), 0, actionCollection(),
01404 "text_list" );
01405 listAction->setItems( styleItems );
01406 connect( listAction, SIGNAL( activated( const QString& ) ),
01407 SLOT( slotListAction( const QString& ) ) );
01408 fontAction = new KFontAction( "Select Font", 0, actionCollection(),
01409 "text_font" );
01410 connect( fontAction, SIGNAL( activated( const QString& ) ),
01411 SLOT( slotFontAction( const QString& ) ) );
01412 fontSizeAction = new KFontSizeAction( "Select Size", 0, actionCollection(),
01413 "text_size" );
01414 connect( fontSizeAction, SIGNAL( fontSizeChanged( int ) ),
01415 SLOT( slotSizeAction( int ) ) );
01416
01417 alignLeftAction = new KToggleAction (i18n("Align Left"), "text_left", 0,
01418 this, SLOT(slotAlignLeft()), actionCollection(),
01419 "align_left");
01420 alignLeftAction->setChecked( TRUE );
01421 alignRightAction = new KToggleAction (i18n("Align Right"), "text_right", 0,
01422 this, SLOT(slotAlignRight()), actionCollection(),
01423 "align_right");
01424 alignCenterAction = new KToggleAction (i18n("Align Center"), "text_center", 0,
01425 this, SLOT(slotAlignCenter()), actionCollection(),
01426 "align_center");
01427 textBoldAction = new KToggleAction( i18n("&Bold"), "text_bold", CTRL+Key_B,
01428 this, SLOT(slotTextBold()),
01429 actionCollection(), "text_bold");
01430 textItalicAction = new KToggleAction( i18n("&Italic"), "text_italic", CTRL+Key_I,
01431 this, SLOT(slotTextItalic()),
01432 actionCollection(), "text_italic");
01433 textUnderAction = new KToggleAction( i18n("&Underline"), "text_under", CTRL+Key_U,
01434 this, SLOT(slotTextUnder()),
01435 actionCollection(), "text_under");
01436 actionFormatReset = new KAction( i18n( "Reset Font Settings" ), "eraser", 0,
01437 this, SLOT( slotFormatReset() ),
01438 actionCollection(), "format_reset");
01439 actionFormatColor = new KAction( i18n( "Text Color..." ), "colorize", 0,
01440 this, SLOT( slotTextColor() ),
01441 actionCollection(), "format_color");
01442
01443
01444 createGUI("kmcomposerui.rc");
01445
01446 connect( toolBar("htmlToolBar"), SIGNAL( visibilityChanged(bool) ),
01447 this, SLOT( htmlToolBarVisibilityChanged(bool) ) );
01448
01449
01450
01451 KAction* configureAction = actionCollection()->action("options_configure" );
01452 if ( configureAction )
01453 configureAction->setText( i18n("Configure KMail" ) );
01454 }
01455
01456
01457 void KMComposeWin::setupStatusBar(void)
01458 {
01459 statusBar()->insertItem("", 0, 1);
01460 statusBar()->setItemAlignment(0, AlignLeft | AlignVCenter);
01461
01462 statusBar()->insertItem(i18n( " Spellcheck: %1 ").arg( " " ), 3, 0, true );
01463 statusBar()->insertItem(i18n( " Column: %1 ").arg(" "), 2, 0, true);
01464 statusBar()->insertItem(i18n( " Line: %1 ").arg(" "), 1, 0, true);
01465 }
01466
01467
01468
01469 void KMComposeWin::updateCursorPosition()
01470 {
01471 int col,line;
01472 QString temp;
01473 line = mEditor->currentLine();
01474 col = mEditor->currentColumn();
01475 temp = i18n(" Line: %1 ").arg(line+1);
01476 statusBar()->changeItem(temp,1);
01477 temp = i18n(" Column: %1 ").arg(col+1);
01478 statusBar()->changeItem(temp,2);
01479 }
01480
01481
01482
01483 void KMComposeWin::setupEditor(void)
01484 {
01485
01486 mEditor->setModified(FALSE);
01487 QFontMetrics fm(mBodyFont);
01488 mEditor->setTabStopWidth(fm.width(QChar(' ')) * 8);
01489
01490
01491 if (GlobalSettings::self()->wordWrap())
01492 {
01493 mEditor->setWordWrap( QTextEdit::FixedColumnWidth );
01494 mEditor->setWrapColumnOrWidth( GlobalSettings::self()->lineWrapWidth() );
01495 }
01496 else
01497 {
01498 mEditor->setWordWrap( QTextEdit::NoWrap );
01499 }
01500
01501
01502 slotUpdateFont();
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525 updateCursorPosition();
01526 connect(mEditor,SIGNAL(CursorPositionChanged()),SLOT(updateCursorPosition()));
01527 connect( mEditor, SIGNAL( currentFontChanged( const QFont & ) ),
01528 this, SLOT( fontChanged( const QFont & ) ) );
01529 connect( mEditor, SIGNAL( currentAlignmentChanged( int ) ),
01530 this, SLOT( alignmentChanged( int ) ) );
01531
01532 }
01533
01534
01535
01536 static QString cleanedUpHeaderString( const QString & s )
01537 {
01538
01539 QString res( s );
01540 res.replace( '\r', "" );
01541 res.replace( '\n', " " );
01542 return res.stripWhiteSpace();
01543 }
01544
01545
01546 QString KMComposeWin::subject() const
01547 {
01548 return cleanedUpHeaderString( mEdtSubject->text() );
01549 }
01550
01551
01552 QString KMComposeWin::to() const
01553 {
01554 if ( mEdtTo ) {
01555 return cleanedUpHeaderString( mEdtTo->text() );
01556 } else if ( mRecipientsEditor ) {
01557 return mRecipientsEditor->recipientString( Recipient::To );
01558 } else {
01559 return QString::null;
01560 }
01561 }
01562
01563
01564 QString KMComposeWin::cc() const
01565 {
01566 if ( mEdtCc && !mEdtCc->isHidden() ) {
01567 return cleanedUpHeaderString( mEdtCc->text() );
01568 } else if ( mRecipientsEditor ) {
01569 return mRecipientsEditor->recipientString( Recipient::Cc );
01570 } else {
01571 return QString::null;
01572 }
01573 }
01574
01575
01576 QString KMComposeWin::bcc() const
01577 {
01578 if ( mEdtBcc && !mEdtBcc->isHidden() ) {
01579 return cleanedUpHeaderString( mEdtBcc->text() );
01580 } else if ( mRecipientsEditor ) {
01581 return mRecipientsEditor->recipientString( Recipient::Bcc );
01582 } else {
01583 return QString::null;
01584 }
01585 }
01586
01587
01588 QString KMComposeWin::from() const
01589 {
01590 return cleanedUpHeaderString( mEdtFrom->text() );
01591 }
01592
01593
01594 QString KMComposeWin::replyTo() const
01595 {
01596 if ( mEdtReplyTo ) {
01597 return cleanedUpHeaderString( mEdtReplyTo->text() );
01598 } else {
01599 return QString::null;
01600 }
01601 }
01602
01603
01604 void KMComposeWin::verifyWordWrapLengthIsAdequate(const QString &body)
01605 {
01606 int maxLineLength = 0;
01607 int curPos;
01608 int oldPos = 0;
01609 if (mEditor->QTextEdit::wordWrap() == QTextEdit::FixedColumnWidth) {
01610 for (curPos = 0; curPos < (int)body.length(); ++curPos)
01611 if (body[curPos] == '\n') {
01612 if ((curPos - oldPos) > maxLineLength)
01613 maxLineLength = curPos - oldPos;
01614 oldPos = curPos;
01615 }
01616 if ((curPos - oldPos) > maxLineLength)
01617 maxLineLength = curPos - oldPos;
01618 if (mEditor->wrapColumnOrWidth() < maxLineLength)
01619 mEditor->setWrapColumnOrWidth(maxLineLength);
01620 }
01621 }
01622
01623
01624 void KMComposeWin::decryptOrStripOffCleartextSignature( QCString& body )
01625 {
01626 QPtrList<Kpgp::Block> pgpBlocks;
01627 QStrList nonPgpBlocks;
01628 if( Kpgp::Module::prepareMessageForDecryption( body,
01629 pgpBlocks, nonPgpBlocks ) )
01630 {
01631
01632
01633 if( pgpBlocks.count() == 1 )
01634 {
01635 Kpgp::Block* block = pgpBlocks.first();
01636 if( ( block->type() == Kpgp::PgpMessageBlock ) ||
01637 ( block->type() == Kpgp::ClearsignedBlock ) )
01638 {
01639 if( block->type() == Kpgp::PgpMessageBlock )
01640
01641 block->decrypt();
01642 else
01643
01644 block->verify();
01645
01646 body = nonPgpBlocks.first()
01647 + block->text()
01648 + nonPgpBlocks.last();
01649 }
01650 }
01651 }
01652 }
01653
01654
01655 void KMComposeWin::setTransport( const QString & transport )
01656 {
01657 kdDebug(5006) << "KMComposeWin::setTransport( \"" << transport << "\" )" << endl;
01658
01659 if ( transport.isEmpty() )
01660 return;
01661
01662 bool transportFound = false;
01663 for ( int i = 0; i < mTransport->count(); ++i ) {
01664 if ( mTransport->text(i) == transport ) {
01665 transportFound = true;
01666 mTransport->setCurrentItem(i);
01667 kdDebug(5006) << "transport found, it's no. " << i << " in the list" << endl;
01668 break;
01669 }
01670 }
01671 if ( !transportFound ) {
01672 kdDebug(5006) << "unknown transport \"" << transport << "\"" << endl;
01673 if ( transport.startsWith("smtp://") || transport.startsWith("smtps://") ||
01674 transport.startsWith("file://") ) {
01675
01676 mTransport->setEditText( transport );
01677 }
01678 else {
01679
01680 mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
01681 }
01682 }
01683 }
01684
01685
01686 void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
01687 bool allowDecryption, bool isModified)
01688 {
01689
01690 if(!newMsg)
01691 {
01692 kdDebug(5006) << "KMComposeWin::setMsg() : newMsg == 0!" << endl;
01693 return;
01694 }
01695 mMsg = newMsg;
01696
01697 mEdtFrom->setText(mMsg->from());
01698 mEdtReplyTo->setText(mMsg->replyTo());
01699 if ( mClassicalRecipients ) {
01700 mEdtTo->setText(mMsg->to());
01701 mEdtCc->setText(mMsg->cc());
01702 mEdtBcc->setText(mMsg->bcc());
01703 } else {
01704 mRecipientsEditor->setRecipientString( mMsg->to(), Recipient::To );
01705 mRecipientsEditor->setRecipientString( mMsg->cc(), Recipient::Cc );
01706 mRecipientsEditor->setRecipientString( mMsg->bcc(), Recipient::Bcc );
01707 }
01708 mEdtSubject->setText(mMsg->subject());
01709
01710 if (!mBtnIdentity->isChecked() && !newMsg->headerField("X-KMail-Identity").isEmpty())
01711 mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
01712
01713
01714
01715 if ( !mBtnIdentity->isChecked() ) {
01716 disconnect(mIdentity,SIGNAL(identityChanged(uint)),
01717 this, SLOT(slotIdentityChanged(uint)));
01718 }
01719 mIdentity->setCurrentIdentity( mId );
01720 if ( !mBtnIdentity->isChecked() ) {
01721 connect(mIdentity,SIGNAL(identityChanged(uint)),
01722 this, SLOT(slotIdentityChanged(uint)));
01723 }
01724 else {
01725
01726
01727
01728 slotIdentityChanged( mId );
01729 }
01730
01731 KPIM::IdentityManager * im = kmkernel->identityManager();
01732
01733 const KPIM::Identity & ident = im->identityForUoid( mIdentity->currentIdentity() );
01734
01735
01736
01737 QString mdnAddr = newMsg->headerField("Disposition-Notification-To");
01738 mRequestMDNAction->setChecked( ( !mdnAddr.isEmpty() &&
01739 im->thatIsMe( mdnAddr ) ) ||
01740 GlobalSettings::self()->requestMDN() );
01741
01742
01743 mUrgentAction->setChecked( newMsg->isUrgent() );
01744
01745 if (!ident.isXFaceEnabled() || ident.xface().isEmpty())
01746 mMsg->removeHeaderField("X-Face");
01747 else
01748 {
01749 QString xface = ident.xface();
01750 if (!xface.isEmpty())
01751 {
01752 int numNL = ( xface.length() - 1 ) / 70;
01753 for ( int i = numNL; i > 0; --i )
01754 xface.insert( i*70, "\n\t" );
01755 mMsg->setHeaderField("X-Face", xface);
01756 }
01757 }
01758
01759
01760 switch ( mMsg->encryptionState() ) {
01761 case KMMsgFullyEncrypted:
01762 case KMMsgPartiallyEncrypted:
01763 mLastEncryptActionState = true;
01764 break;
01765 case KMMsgNotEncrypted:
01766 mLastEncryptActionState = false;
01767 break;
01768 default:
01769 break;
01770 }
01771
01772
01773 switch ( mMsg->signatureState() ) {
01774 case KMMsgFullySigned:
01775 case KMMsgPartiallySigned:
01776 mLastSignActionState = true;
01777 break;
01778 case KMMsgNotSigned:
01779 mLastSignActionState = false;
01780 break;
01781 default:
01782 break;
01783 }
01784
01785 mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
01786 mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
01787
01788 if ( Kleo::CryptoBackendFactory::instance()->openpgp() || Kleo::CryptoBackendFactory::instance()->smime() ) {
01789 const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
01790 && !ident.pgpSigningKey().isEmpty();
01791 const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
01792 && !ident.smimeSigningKey().isEmpty();
01793
01794 setEncryption( mLastEncryptActionState );
01795 setSigning( ( canOpenPGPSign || canSMIMESign ) && mLastSignActionState );
01796 }
01797
01798
01799
01800 mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
01801 !ident.pgpEncryptionKey().isEmpty() );
01802
01803 QString transport = newMsg->headerField("X-KMail-Transport");
01804 if (!mBtnTransport->isChecked() && !transport.isEmpty())
01805 setTransport( transport );
01806
01807 if (!mBtnFcc->isChecked())
01808 {
01809 if (!mMsg->fcc().isEmpty())
01810 setFcc(mMsg->fcc());
01811 else
01812 setFcc(ident.fcc());
01813 }
01814
01815 mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
01816
01817 partNode * root = partNode::fromMessage( mMsg );
01818
01819 KMail::ObjectTreeParser otp;
01820 otp.parseObjectTree( root );
01821
01822 KMail::AttachmentCollector ac;
01823 ac.setDiveIntoEncryptions( true );
01824 ac.setDiveIntoSignatures( true );
01825 ac.setDiveIntoMessages( false );
01826
01827 ac.collectAttachmentsFrom( root );
01828
01829 for ( std::vector<partNode*>::const_iterator it = ac.attachments().begin() ; it != ac.attachments().end() ; ++it )
01830 addAttach( new KMMessagePart( (*it)->msgPart() ) );
01831
01832 mEditor->setText( otp.textualContent() );
01833 mCharset = otp.textualContentCharset();
01834 if ( mCharset.isEmpty() )
01835 mCharset = mMsg->charset();
01836 if ( mCharset.isEmpty() )
01837 mCharset = mDefCharset;
01838 setCharset( mCharset );
01839
01840 if ( partNode * n = root->findType( DwMime::kTypeText, DwMime::kSubtypeHtml ) )
01841 if ( partNode * p = n->parentNode() )
01842 if ( p->hasType( DwMime::kTypeMultipart ) &&
01843 p->hasSubType( DwMime::kSubtypeAlternative ) )
01844 if ( mMsg->headerField( "X-KMail-Markup" ) == "true" ) {
01845 toggleMarkup( true );
01846 mEditor->setText(n->encodedBody() );
01847 }
01848
01849 if ( mMsg->numBodyParts() == 0 && otp.textualContent().isEmpty() ) {
01850 mCharset=mMsg->charset();
01851 if ( mCharset.isEmpty() || mCharset == "default" )
01852 mCharset = mDefCharset;
01853
01854 QCString bodyDecoded = mMsg->bodyDecoded();
01855
01856 if( allowDecryption )
01857 decryptOrStripOffCleartextSignature( bodyDecoded );
01858
01859 const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
01860 if (codec) {
01861 mEditor->setText(codec->toUnicode(bodyDecoded));
01862 } else
01863 mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
01864 }
01865
01866
01867 #ifdef BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
01868 const int num = mMsg->numBodyParts();
01869 kdDebug(5006) << "KMComposeWin::setMsg() mMsg->numBodyParts="
01870 << mMsg->numBodyParts() << endl;
01871
01872 if ( num > 0 ) {
01873 KMMessagePart bodyPart;
01874 int firstAttachment = 0;
01875
01876 mMsg->bodyPart(1, &bodyPart);
01877 if ( bodyPart.typeStr().lower() == "text" &&
01878 bodyPart.subtypeStr().lower() == "html" ) {
01879
01880 partNode *root = partNode::fromMessage( mMsg );
01881 partNode *node = root->findType( DwMime::kTypeText,
01882 DwMime::kSubtypeHtml );
01883 if ( node && node->parentNode() &&
01884 node->parentNode()->hasType( DwMime::kTypeMultipart ) &&
01885 node->parentNode()->hasSubType( DwMime::kSubtypeAlternative ) ) {
01886
01887 kdDebug(5006) << "KMComposeWin::setMsg() : text/html found" << endl;
01888 firstAttachment = 2;
01889 if ( mMsg->headerField( "X-KMail-Markup" ) == "true" )
01890 toggleMarkup( true );
01891 }
01892 delete root; root = 0;
01893 }
01894 if ( firstAttachment == 0 ) {
01895 mMsg->bodyPart(0, &bodyPart);
01896 if ( bodyPart.typeStr().lower() == "text" ) {
01897
01898 kdDebug(5006) << "KMComposeWin::setMsg() : text/* found" << endl;
01899 firstAttachment = 1;
01900 }
01901 }
01902
01903 if ( firstAttachment != 0 )
01904 {
01905 mCharset = bodyPart.charset();
01906 if ( mCharset.isEmpty() || mCharset == "default" )
01907 mCharset = mDefCharset;
01908
01909 QCString bodyDecoded = bodyPart.bodyDecoded();
01910
01911 if( allowDecryption )
01912 decryptOrStripOffCleartextSignature( bodyDecoded );
01913
01914
01915
01916
01917
01918
01919
01920 const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
01921 if (codec)
01922 mEditor->setText(codec->toUnicode(bodyDecoded));
01923 else
01924 mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
01925
01926 } else mEditor->setText("");
01927 for( int i = firstAttachment; i < num; ++i )
01928 {
01929 KMMessagePart *msgPart = new KMMessagePart;
01930 mMsg->bodyPart(i, msgPart);
01931 QCString mimeType = msgPart->typeStr().lower() + '/'
01932 + msgPart->subtypeStr().lower();
01933
01934
01935 if( mimeType != "application/pgp-signature" ) {
01936 addAttach(msgPart);
01937 }
01938 }
01939 } else{
01940 mCharset=mMsg->charset();
01941 if ( mCharset.isEmpty() || mCharset == "default" )
01942 mCharset = mDefCharset;
01943
01944 QCString bodyDecoded = mMsg->bodyDecoded();
01945
01946 if( allowDecryption )
01947 decryptOrStripOffCleartextSignature( bodyDecoded );
01948
01949 const QTextCodec *codec = KMMsgBase::codecForName(mCharset);
01950 if (codec) {
01951 mEditor->setText(codec->toUnicode(bodyDecoded));
01952 } else
01953 mEditor->setText(QString::fromLocal8Bit(bodyDecoded));
01954 }
01955
01956 setCharset(mCharset);
01957 #endif // BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
01958
01959 if( (GlobalSettings::self()->autoTextSignature()=="auto") && mayAutoSign ) {
01960
01961
01962
01963
01964
01965
01966 QTimer::singleShot( 200, this, SLOT(slotAppendSignature()) );
01967 }
01968 setModified( isModified );
01969 }
01970
01971
01972
01973 void KMComposeWin::setFcc( const QString &idString )
01974 {
01975
01976 if ( ! idString.isEmpty() && kmkernel->findFolderById( idString ) ) {
01977 mFcc->setFolder( idString );
01978 } else {
01979 mFcc->setFolder( kmkernel->sentFolder() );
01980 }
01981 }
01982
01983
01984
01985 bool KMComposeWin::isModified() const
01986 {
01987 return ( mEditor->isModified() ||
01988 mEdtFrom->edited() ||
01989 ( mEdtReplyTo && mEdtReplyTo->edited() ) ||
01990 ( mEdtTo && mEdtTo->edited() ) ||
01991 ( mEdtCc && mEdtCc->edited() ) ||
01992 ( mEdtBcc && mEdtBcc->edited() ) ||
01993 ( mRecipientsEditor && mRecipientsEditor->isModified() ) ||
01994 mEdtSubject->edited() ||
01995 mAtmModified ||
01996 ( mTransport->lineEdit() && mTransport->lineEdit()->edited() ) );
01997 }
01998
01999
02000
02001 void KMComposeWin::setModified( bool modified )
02002 {
02003 mEditor->setModified( modified );
02004 if ( !modified ) {
02005 mEdtFrom->setEdited( false );
02006 if ( mEdtReplyTo ) mEdtReplyTo->setEdited( false );
02007 if ( mEdtTo ) mEdtTo->setEdited( false );
02008 if ( mEdtCc ) mEdtCc->setEdited( false );
02009 if ( mEdtBcc ) mEdtBcc->setEdited( false );
02010 if ( mRecipientsEditor ) mRecipientsEditor->clearModified();
02011 mEdtSubject->setEdited( false );
02012 mAtmModified = false ;
02013 if ( mTransport->lineEdit() )
02014 mTransport->lineEdit()->setEdited( false );
02015 }
02016 }
02017
02018
02019
02020 bool KMComposeWin::queryClose ()
02021 {
02022 if ( !mEditor->checkExternalEditorFinished() )
02023 return false;
02024 if (kmkernel->shuttingDown() || kapp->sessionSaving())
02025 return true;
02026
02027 if ( isModified() ) {
02028 const int rc = KMessageBox::warningYesNoCancel(this,
02029 i18n("Do you want to save the message for later or discard it?"),
02030 i18n("Close Composer"),
02031 KGuiItem(i18n("&Save as Draft"), "filesave", QString::null,
02032 i18n("Save this message in the Drafts folder. It can "
02033 "then be edited and sent at a later time.")),
02034 KStdGuiItem::discard() );
02035 if (rc == KMessageBox::Cancel)
02036 return false;
02037 else if (rc == KMessageBox::Yes) {
02038
02039 slotSaveDraft();
02040 return false;
02041 }
02042 }
02043 cleanupAutoSave();
02044 return true;
02045 }
02046
02047
02048 bool KMComposeWin::userForgotAttachment()
02049 {
02050 bool checkForForgottenAttachments = GlobalSettings::self()->showForgottenAttachmentWarning();
02051
02052 if ( !checkForForgottenAttachments || ( mAtmList.count() > 0 ) )
02053 return false;
02054
02055
02056 QStringList attachWordsList = GlobalSettings::self()->attachmentKeywords();
02057
02058 if ( attachWordsList.isEmpty() ) {
02059
02060 attachWordsList << QString::fromLatin1("attachment")
02061 << QString::fromLatin1("attached");
02062 if ( QString::fromLatin1("attachment") != i18n("attachment") )
02063 attachWordsList << i18n("attachment");
02064 if ( QString::fromLatin1("attached") != i18n("attached") )
02065 attachWordsList << i18n("attached");
02066 }
02067
02068 QRegExp rx ( QString::fromLatin1("\\b") +
02069 attachWordsList.join("\\b|\\b") +
02070 QString::fromLatin1("\\b") );
02071 rx.setCaseSensitive( false );
02072
02073 bool gotMatch = false;
02074
02075
02076
02077 QString subj = subject();
02078 gotMatch = ( KMMessage::stripOffPrefixes( subj ) == subj )
02079 && ( rx.search( subj ) >= 0 );
02080
02081 if ( !gotMatch ) {
02082
02083
02084 QRegExp quotationRx ("^([ \\t]*([|>:}#]|[A-Za-z]+>))+");
02085 for ( int i = 0; i < mEditor->numLines(); ++i ) {
02086 QString line = mEditor->textLine( i );
02087 gotMatch = ( quotationRx.search( line ) < 0 )
02088 && ( rx.search( line ) >= 0 );
02089 if ( gotMatch )
02090 break;
02091 }
02092 }
02093
02094 if ( !gotMatch )
02095 return false;
02096
02097 int rc = KMessageBox::warningYesNoCancel( this,
02098 i18n("The message you have composed seems to refer to an "
02099 "attached file but you have not attached anything.\n"
02100 "Do you want to attach a file to your message?"),
02101 i18n("File Attachment Reminder"),
02102 i18n("&Attach File..."),
02103 i18n("&Send as Is") );
02104 if ( rc == KMessageBox::Cancel )
02105 return true;
02106 if ( rc == KMessageBox::Yes ) {
02107 slotAttachFile();
02108
02109 return true;
02110 }
02111 return false;
02112 }
02113
02114
02115 void KMComposeWin::applyChanges( bool dontSignNorEncrypt, bool dontDisable )
02116 {
02117 kdDebug(5006) << "entering KMComposeWin::applyChanges" << endl;
02118
02119 if(!mMsg) {
02120 kdDebug(5006) << "KMComposeWin::applyChanges() : mMsg == 0!\n" << endl;
02121 emit applyChangesDone( false );
02122 return;
02123 }
02124
02125 if( mComposer ) {
02126 kdDebug(5006) << "KMComposeWin::applyChanges() : applyChanges called twice"
02127 << endl;
02128 return;
02129 }
02130
02131
02132 mComposer = new MessageComposer( this );
02133 connect( mComposer, SIGNAL( done( bool ) ),
02134 this, SLOT( slotComposerDone( bool ) ) );
02135
02136
02137
02138
02139 if ( !dontDisable ) setEnabled( false );
02140
02141 mComposer->setDisableBreaking( mDisableBreaking );
02142 mComposer->applyChanges( dontSignNorEncrypt );
02143 }
02144
02145 void KMComposeWin::slotComposerDone( bool rc )
02146 {
02147 deleteAll( mComposedMessages );
02148 mComposedMessages = mComposer->composedMessageList();
02149 emit applyChangesDone( rc );
02150 delete mComposer;
02151 mComposer = 0;
02152
02153
02154 setEnabled( true );
02155 }
02156
02157 const KPIM::Identity & KMComposeWin::identity() const {
02158 return kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
02159 }
02160
02161 uint KMComposeWin::identityUid() const {
02162 return mIdentity->currentIdentity();
02163 }
02164
02165 Kleo::CryptoMessageFormat KMComposeWin::cryptoMessageFormat() const {
02166 if ( !mCryptoModuleAction )
02167 return Kleo::AutoFormat;
02168 return cb2format( mCryptoModuleAction->currentItem() );
02169 }
02170
02171 bool KMComposeWin::encryptToSelf() const {
02172 return !Kpgp::Module::getKpgp() || Kpgp::Module::getKpgp()->encryptToSelf();
02173 }
02174
02175 bool KMComposeWin::queryExit ()
02176 {
02177 return true;
02178 }
02179
02180
02181 void KMComposeWin::addAttach(const KURL aUrl)
02182 {
02183 if ( !aUrl.isValid() ) {
02184 KMessageBox::sorry( this, i18n( "<qt><p>KMail could not recognize the location of the attachment (%1);</p>"
02185 "<p>you have to specify the full path if you wish to attach a file.</p></qt>" )
02186 .arg( aUrl.prettyURL() ) );
02187 return;
02188 }
02189 KIO::TransferJob *job = KIO::get(aUrl);
02190 KIO::Scheduler::scheduleJob( job );
02191 atmLoadData ld;
02192 ld.url = aUrl;
02193 ld.data = QByteArray();
02194 ld.insert = false;
02195 if( !aUrl.fileEncoding().isEmpty() )
02196 ld.encoding = aUrl.fileEncoding().latin1();
02197
02198 mMapAtmLoadData.insert(job, ld);
02199 connect(job, SIGNAL(result(KIO::Job *)),
02200 this, SLOT(slotAttachFileResult(KIO::Job *)));
02201 connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
02202 this, SLOT(slotAttachFileData(KIO::Job *, const QByteArray &)));
02203 }
02204
02205
02206
02207 void KMComposeWin::addAttach(const KMMessagePart* msgPart)
02208 {
02209 mAtmList.append(msgPart);
02210
02211
02212 if (mAtmList.count()==1)
02213 {
02214 mAtmListView->resize(mAtmListView->width(), 50);
02215 mAtmListView->show();
02216 resize(size());
02217 }
02218
02219
02220 KMAtmListViewItem *lvi = new KMAtmListViewItem( mAtmListView );
02221 msgPartToItem(msgPart, lvi);
02222 mAtmItemList.append(lvi);
02223
02224
02225 if ( mTempDir != 0 ) {
02226 delete mTempDir;
02227 mTempDir = 0;
02228 }
02229
02230 connect( lvi, SIGNAL( compress( int ) ),
02231 this, SLOT( compressAttach( int ) ) );
02232 connect( lvi, SIGNAL( uncompress( int ) ),
02233 this, SLOT( uncompressAttach( int ) ) );
02234
02235 slotUpdateAttachActions();
02236 }
02237
02238
02239
02240 void KMComposeWin::slotUpdateAttachActions()
02241 {
02242 int selectedCount = 0;
02243 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it ) {
02244 if ( (*it)->isSelected() ) {
02245 ++selectedCount;
02246 }
02247 }
02248
02249 mAttachRemoveAction->setEnabled( selectedCount >= 1 );
02250 mAttachSaveAction->setEnabled( selectedCount == 1 );
02251 mAttachPropertiesAction->setEnabled( selectedCount == 1 );
02252 }
02253
02254
02255
02256
02257 QString KMComposeWin::prettyMimeType( const QString& type )
02258 {
02259 QString t = type.lower();
02260 KServiceType::Ptr st = KServiceType::serviceType( t );
02261 return st ? st->comment() : t;
02262 }
02263
02264 void KMComposeWin::msgPartToItem(const KMMessagePart* msgPart,
02265 KMAtmListViewItem *lvi, bool loadDefaults)
02266 {
02267 assert(msgPart != 0);
02268
02269 if (!msgPart->fileName().isEmpty())
02270 lvi->setText(0, msgPart->fileName());
02271 else
02272 lvi->setText(0, msgPart->name());
02273 lvi->setText(1, KIO::convertSize( msgPart->decodedSize()));
02274 lvi->setText(2, msgPart->contentTransferEncodingStr());
02275 lvi->setText(3, prettyMimeType(msgPart->typeStr() + "/" + msgPart->subtypeStr()));
02276
02277 if ( loadDefaults ) {
02278 if( canSignEncryptAttachments() ) {
02279 lvi->enableCryptoCBs( true );
02280 lvi->setEncrypt( mEncryptAction->isChecked() );
02281 lvi->setSign( mSignAction->isChecked() );
02282 } else {
02283 lvi->enableCryptoCBs( false );
02284 }
02285 }
02286 }
02287
02288
02289
02290 void KMComposeWin::removeAttach(const QString &aUrl)
02291 {
02292 int idx;
02293 KMMessagePart* msgPart;
02294 for(idx=0,msgPart=mAtmList.first(); msgPart;
02295 msgPart=mAtmList.next(),idx++) {
02296 if (msgPart->name() == aUrl) {
02297 removeAttach(idx);
02298 return;
02299 }
02300 }
02301 }
02302
02303
02304
02305 void KMComposeWin::removeAttach(int idx)
02306 {
02307 mAtmModified = TRUE;
02308 mAtmList.remove(idx);
02309 delete mAtmItemList.take(idx);
02310
02311 if( mAtmList.isEmpty() )
02312 {
02313 mAtmListView->hide();
02314 mAtmListView->setMinimumSize(0, 0);
02315 resize(size());
02316 }
02317 }
02318
02319
02320
02321 bool KMComposeWin::encryptFlagOfAttachment(int idx)
02322 {
02323 return (int)(mAtmItemList.count()) > idx
02324 ? static_cast<KMAtmListViewItem*>( mAtmItemList.at( idx ) )->isEncrypt()
02325 : false;
02326 }
02327
02328
02329
02330 bool KMComposeWin::signFlagOfAttachment(int idx)
02331 {
02332 return (int)(mAtmItemList.count()) > idx
02333 ? ((KMAtmListViewItem*)(mAtmItemList.at( idx )))->isSign()
02334 : false;
02335 }
02336
02337
02338
02339 void KMComposeWin::addrBookSelInto()
02340 {
02341 if ( mClassicalRecipients ) {
02342 if ( GlobalSettings::self()->addresseeSelectorType() ==
02343 GlobalSettings::EnumAddresseeSelectorType::New ) {
02344 addrBookSelIntoNew();
02345 } else {
02346 addrBookSelIntoOld();
02347 }
02348 } else {
02349 kdWarning() << "To be implemented: call recipients picker." << endl;
02350 }
02351 }
02352
02353 void KMComposeWin::addrBookSelIntoOld()
02354 {
02355 AddressesDialog dlg( this );
02356 QString txt;
02357 QStringList lst;
02358
02359 txt = to();
02360 if ( !txt.isEmpty() ) {
02361 lst = KPIM::splitEmailAddrList( txt );
02362 dlg.setSelectedTo( lst );
02363 }
02364
02365 txt = mEdtCc->text();
02366 if ( !txt.isEmpty() ) {
02367 lst = KPIM::splitEmailAddrList( txt );
02368 dlg.setSelectedCC( lst );
02369 }
02370
02371 txt = mEdtBcc->text();
02372 if ( !txt.isEmpty() ) {
02373 lst = KPIM::splitEmailAddrList( txt );
02374 dlg.setSelectedBCC( lst );
02375 }
02376
02377 dlg.setRecentAddresses( RecentAddresses::self( KMKernel::config() )->kabcAddresses() );
02378
02379 if (dlg.exec()==QDialog::Rejected) return;
02380
02381 mEdtTo->setText( dlg.to().join(", ") );
02382 mEdtTo->setEdited( true );
02383
02384 mEdtCc->setText( dlg.cc().join(", ") );
02385 mEdtCc->setEdited( true );
02386
02387 mEdtBcc->setText( dlg.bcc().join(", ") );
02388 mEdtBcc->setEdited( true );
02389
02390
02391 if ( !mEdtBcc->text().isEmpty() ) {
02392 mShowHeaders |= HDR_BCC;
02393 rethinkFields( false );
02394 }
02395 }
02396
02397 void KMComposeWin::addrBookSelIntoNew()
02398 {
02399 AddresseeEmailSelection selection;
02400
02401 AddresseeSelectorDialog dlg( &selection );
02402
02403 QString txt;
02404 QStringList lst;
02405
02406 txt = to();
02407 if ( !txt.isEmpty() ) {
02408 lst = KPIM::splitEmailAddrList( txt );
02409 selection.setSelectedTo( lst );
02410 }
02411
02412 txt = mEdtCc->text();
02413 if ( !txt.isEmpty() ) {
02414 lst = KPIM::splitEmailAddrList( txt );
02415 selection.setSelectedCC( lst );
02416 }
02417
02418 txt = mEdtBcc->text();
02419 if ( !txt.isEmpty() ) {
02420 lst = KPIM::splitEmailAddrList( txt );
02421 selection.setSelectedBCC( lst );
02422 }
02423
02424 if (dlg.exec()==QDialog::Rejected) return;
02425
02426 QStringList list = selection.to() + selection.toDistributionLists();
02427 mEdtTo->setText( list.join(", ") );
02428 mEdtTo->setEdited( true );
02429
02430 list = selection.cc() + selection.ccDistributionLists();
02431 mEdtCc->setText( list.join(", ") );
02432 mEdtCc->setEdited( true );
02433
02434 list = selection.bcc() + selection.bccDistributionLists();
02435 mEdtBcc->setText( list.join(", ") );
02436 mEdtBcc->setEdited( true );
02437
02438
02439 if ( !mEdtBcc->text().isEmpty() ) {
02440 mShowHeaders |= HDR_BCC;
02441 rethinkFields( false );
02442 }
02443 }
02444
02445
02446
02447 void KMComposeWin::setCharset(const QCString& aCharset, bool forceDefault)
02448 {
02449 if ((forceDefault && GlobalSettings::self()->forceReplyCharset()) || aCharset.isEmpty())
02450 mCharset = mDefCharset;
02451 else
02452 mCharset = aCharset.lower();
02453
02454 if ( mCharset.isEmpty() || mCharset == "default" )
02455 mCharset = mDefCharset;
02456
02457 if (mAutoCharset)
02458 {
02459 mEncodingAction->setCurrentItem( 0 );
02460 return;
02461 }
02462
02463 QStringList encodings = mEncodingAction->items();
02464 int i = 0;
02465 bool charsetFound = FALSE;
02466 for ( QStringList::Iterator it = encodings.begin(); it != encodings.end();
02467 ++it, i++ )
02468 {
02469 if (i > 0 && ((mCharset == "us-ascii" && i == 1) ||
02470 (i != 1 && KGlobal::charsets()->codecForName(
02471 KGlobal::charsets()->encodingForName(*it))
02472 == KGlobal::charsets()->codecForName(mCharset))))
02473 {
02474 mEncodingAction->setCurrentItem( i );
02475 slotSetCharset();
02476 charsetFound = TRUE;
02477 break;
02478 }
02479 }
02480 if (!aCharset.isEmpty() && !charsetFound) setCharset("", TRUE);
02481 }
02482
02483
02484
02485 void KMComposeWin::slotAddrBook()
02486 {
02487 KAddrBookExternal::openAddressBook(this);
02488 }
02489
02490
02491
02492 void KMComposeWin::slotAddrBookFrom()
02493 {
02494 addrBookSelInto();
02495 }
02496
02497
02498
02499 void KMComposeWin::slotAddrBookReplyTo()
02500 {
02501 addrBookSelInto();
02502 }
02503
02504
02505
02506 void KMComposeWin::slotAddrBookTo()
02507 {
02508 addrBookSelInto();
02509 }
02510
02511
02512 void KMComposeWin::slotAttachFile()
02513 {
02514
02515
02516
02517
02518 KFileDialog fdlg(QString::null, QString::null, this, 0, TRUE);
02519 fdlg.setOperationMode( KFileDialog::Other );
02520 fdlg.setCaption(i18n("Attach File"));
02521 fdlg.okButton()->setGuiItem(KGuiItem(i18n("&Attach"),"fileopen"));
02522 fdlg.setMode(KFile::Files);
02523 fdlg.exec();
02524 KURL::List files = fdlg.selectedURLs();
02525
02526 for (KURL::List::Iterator it = files.begin(); it != files.end(); ++it)
02527 addAttach(*it);
02528 }
02529
02530
02531
02532 void KMComposeWin::slotAttachFileData(KIO::Job *job, const QByteArray &data)
02533 {
02534 QMap<KIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
02535 assert(it != mMapAtmLoadData.end());
02536 QBuffer buff((*it).data);
02537 buff.open(IO_WriteOnly | IO_Append);
02538 buff.writeBlock(data.data(), data.size());
02539 buff.close();
02540 }
02541
02542
02543
02544 void KMComposeWin::slotAttachFileResult(KIO::Job *job)
02545 {
02546 QMap<KIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
02547 assert(it != mMapAtmLoadData.end());
02548 if (job->error())
02549 {
02550 mMapAtmLoadData.remove(it);
02551 job->showErrorDialog();
02552 return;
02553 }
02554 if ((*it).insert)
02555 {
02556 (*it).data.resize((*it).data.size() + 1);
02557 (*it).data[(*it).data.size() - 1] = '\0';
02558 if ( const QTextCodec * codec = KGlobal::charsets()->codecForName((*it).encoding) )
02559 mEditor->insert( codec->toUnicode( (*it).data ) );
02560 else
02561 mEditor->insert( QString::fromLocal8Bit( (*it).data ) );
02562 mMapAtmLoadData.remove(it);
02563 return;
02564 }
02565 const QCString partCharset = (*it).url.fileEncoding().isEmpty()
02566 ? mCharset
02567 : QCString((*it).url.fileEncoding().latin1());
02568
02569 KMMessagePart* msgPart;
02570
02571 KCursorSaver busy(KBusyPtr::busy());
02572 QString name( (*it).url.fileName() );
02573
02574 QString mimeType = static_cast<KIO::MimetypeJob*>(job)->mimetype();
02575
02576 if ( name.isEmpty() ) {
02577
02578
02579 if( mimeType == "text/html" )
02580 name = "index.html";
02581 else {
02582
02583 QStringList patterns( KMimeType::mimeType( mimeType )->patterns() );
02584 QString ext;
02585 if( !patterns.isEmpty() ) {
02586 ext = patterns[0];
02587 int i = ext.findRev( '.' );
02588 if( i == -1 )
02589 ext.prepend( '.' );
02590 else if( i > 0 )
02591 ext = ext.mid( i );
02592 }
02593 name = QString("unknown") += ext;
02594 }
02595 }
02596
02597 name.truncate( 256 );
02598
02599 QCString encoding = KMMsgBase::autoDetectCharset(partCharset,
02600 KMMessage::preferredCharsets(), name);
02601 if (encoding.isEmpty()) encoding = "utf-8";
02602
02603 QCString encName;
02604 if ( GlobalSettings::self()->outlookCompatibleAttachments() )
02605 encName = KMMsgBase::encodeRFC2047String( name, encoding );
02606 else
02607 encName = KMMsgBase::encodeRFC2231String( name, encoding );
02608 bool RFC2231encoded = false;
02609 if ( !GlobalSettings::self()->outlookCompatibleAttachments() )
02610 RFC2231encoded = name != QString( encName );
02611
02612
02613 msgPart = new KMMessagePart;
02614 msgPart->setName(name);
02615 QValueList<int> allowedCTEs;
02616 msgPart->setBodyAndGuessCte((*it).data, allowedCTEs,
02617 !kmkernel->msgSender()->sendQuotedPrintable());
02618 kdDebug(5006) << "autodetected cte: " << msgPart->cteStr() << endl;
02619 int slash = mimeType.find( '/' );
02620 if( slash == -1 )
02621 slash = mimeType.length();
02622 msgPart->setTypeStr( mimeType.left( slash ).latin1() );
02623 msgPart->setSubtypeStr( mimeType.mid( slash + 1 ).latin1() );
02624 msgPart->setContentDisposition(QCString("attachment;\n\tfilename")
02625 + ( RFC2231encoded ? "*=" + encName : "=\"" + encName + '"' ) );
02626
02627 mMapAtmLoadData.remove(it);
02628
02629 msgPart->setCharset(partCharset);
02630
02631
02632 KConfigGroup composer(KMKernel::config(), "Composer");
02633 if ( GlobalSettings::self()->showMessagePartDialogOnAttach() ) {
02634 const KCursorSaver saver( QCursor::ArrowCursor );
02635 KMMsgPartDialogCompat dlg(mMainWidget);
02636 int encodings = 0;
02637 for ( QValueListConstIterator<int> it = allowedCTEs.begin() ;
02638 it != allowedCTEs.end() ; ++it )
02639 switch ( *it ) {
02640 case DwMime::kCteBase64: encodings |= KMMsgPartDialog::Base64; break;
02641 case DwMime::kCteQp: encodings |= KMMsgPartDialog::QuotedPrintable; break;
02642 case DwMime::kCte7bit: encodings |= KMMsgPartDialog::SevenBit; break;
02643 case DwMime::kCte8bit: encodings |= KMMsgPartDialog::EightBit; break;
02644 default: ;
02645 }
02646 dlg.setShownEncodings( encodings );
02647 dlg.setMsgPart(msgPart);
02648 if (!dlg.exec()) {
02649 delete msgPart;
02650 msgPart = 0;
02651 return;
02652 }
02653 }
02654 mAtmModified = TRUE;
02655 if (msgPart->typeStr().lower() != "text") msgPart->setCharset(QCString());
02656
02657
02658 addAttach(msgPart);
02659 }
02660
02661
02662
02663 void KMComposeWin::slotInsertFile()
02664 {
02665 KFileDialog fdlg(QString::null, QString::null, this, 0, TRUE);
02666 fdlg.setOperationMode( KFileDialog::Opening );
02667 fdlg.okButton()->setText(i18n("&Insert"));
02668 fdlg.setCaption(i18n("Insert File"));
02669 fdlg.toolBar()->insertCombo(KMMsgBase::supportedEncodings(FALSE), 4711,
02670 false, 0, 0, 0);
02671 KComboBox *combo = fdlg.toolBar()->getCombo(4711);
02672 for (int i = 0; i < combo->count(); i++)
02673 if (KGlobal::charsets()->codecForName(KGlobal::charsets()->
02674 encodingForName(combo->text(i)))
02675 == QTextCodec::codecForLocale()) combo->setCurrentItem(i);
02676 if (!fdlg.exec()) return;
02677
02678 KURL u = fdlg.selectedURL();
02679 mRecentAction->addURL(u);
02680
02681 {
02682 KConfig *config = KMKernel::config();
02683 KConfigGroupSaver saver( config, "Composer" );
02684 QString encoding = KGlobal::charsets()->encodingForName(combo->currentText()).latin1();
02685 QStringList urls = config->readListEntry( "recent-urls" );
02686 QStringList encodings = config->readListEntry( "recent-encodings" );
02687
02688
02689 uint mMaxRecentFiles = 30;
02690 while (urls.count() > mMaxRecentFiles)
02691 urls.erase( urls.fromLast() );
02692 while (encodings.count() > mMaxRecentFiles)
02693 encodings.erase( encodings.fromLast() );
02694
02695 if (urls.count() != encodings.count()) {
02696 urls.clear();
02697 encodings.clear();
02698 }
02699 urls.prepend( u.prettyURL() );
02700 encodings.prepend( encoding );
02701 config->writeEntry( "recent-urls", urls );
02702 config->writeEntry( "recent-encodings", encodings );
02703 mRecentAction->saveEntries( config );
02704 }
02705 slotInsertRecentFile(u);
02706 }
02707
02708
02709
02710 void KMComposeWin::slotInsertRecentFile(const KURL& u)
02711 {
02712 if (u.fileName().isEmpty()) return;
02713
02714 KIO::Job *job = KIO::get(u);
02715 atmLoadData ld;
02716 ld.url = u;
02717 ld.data = QByteArray();
02718 ld.insert = true;
02719
02720 {
02721 KConfig *config = KMKernel::config();
02722 KConfigGroupSaver saver( config, "Composer" );
02723 QStringList urls = config->readListEntry( "recent-urls" );
02724 QStringList encodings = config->readListEntry( "recent-encodings" );
02725 int index = urls.findIndex( u.prettyURL() );
02726 if (index != -1) {
02727 QString encoding = encodings[ index ];
02728 ld.encoding = encoding.latin1();
02729 }
02730 }
02731 mMapAtmLoadData.insert(job, ld);
02732 connect(job, SIGNAL(result(KIO::Job *)),
02733 this, SLOT(slotAttachFileResult(KIO::Job *)));
02734 connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
02735 this, SLOT(slotAttachFileData(KIO::Job *, const QByteArray &)));
02736 }
02737
02738
02739
02740 void KMComposeWin::slotSetCharset()
02741 {
02742 if (mEncodingAction->currentItem() == 0)
02743 {
02744 mAutoCharset = true;
02745 return;
02746 }
02747 mAutoCharset = false;
02748
02749 mCharset = KGlobal::charsets()->encodingForName( mEncodingAction->
02750 currentText() ).latin1();
02751 }
02752
02753
02754
02755 void KMComposeWin::slotSelectCryptoModule( bool init )
02756 {
02757 if ( !init ) {
02758 setModified( true );
02759 }
02760 if( canSignEncryptAttachments() ) {
02761
02762 if( 0 == mAtmListView->columnWidth( mAtmColEncrypt ) ) {
02763
02764
02765 if( !mAtmList.isEmpty() ) {
02766 for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
02767 lvi;
02768 lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
02769 lvi->setSign( mSignAction->isChecked() );
02770 lvi->setEncrypt( mEncryptAction->isChecked() );
02771 }
02772 }
02773 int totalWidth = 0;
02774
02775 for( int col=0; col < mAtmColEncrypt; col++ )
02776 totalWidth += mAtmListView->columnWidth( col );
02777 int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
02778 - mAtmSignColWidth;
02779
02780
02781 int usedWidth = 0;
02782 for( int col=0; col < mAtmColEncrypt-1; col++ ) {
02783 int newWidth = mAtmListView->columnWidth( col ) * reducedTotalWidth
02784 / totalWidth;
02785 mAtmListView->setColumnWidth( col, newWidth );
02786 usedWidth += newWidth;
02787 }
02788
02789
02790
02791 mAtmListView->setColumnWidth( mAtmColEncrypt-1,
02792 reducedTotalWidth - usedWidth );
02793 mAtmListView->setColumnWidth( mAtmColEncrypt, mAtmEncryptColWidth );
02794 mAtmListView->setColumnWidth( mAtmColSign, mAtmSignColWidth );
02795 for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
02796 lvi;
02797 lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
02798 lvi->enableCryptoCBs( true );
02799 }
02800 }
02801 } else {
02802
02803 if( 0 != mAtmListView->columnWidth( mAtmColEncrypt ) ) {
02804 mAtmEncryptColWidth = mAtmListView->columnWidth( mAtmColEncrypt );
02805 mAtmSignColWidth = mAtmListView->columnWidth( mAtmColSign );
02806 int totalWidth = 0;
02807
02808 for( int col=0; col < mAtmListView->columns(); col++ )
02809 totalWidth += mAtmListView->columnWidth( col );
02810 int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
02811 - mAtmSignColWidth;
02812
02813
02814 int usedWidth = 0;
02815 for( int col=0; col < mAtmColEncrypt-1; col++ ) {
02816 int newWidth = mAtmListView->columnWidth( col ) * totalWidth
02817 / reducedTotalWidth;
02818 mAtmListView->setColumnWidth( col, newWidth );
02819 usedWidth += newWidth;
02820 }
02821
02822
02823
02824 mAtmListView->setColumnWidth( mAtmColEncrypt-1, totalWidth - usedWidth );
02825 mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
02826 mAtmListView->setColumnWidth( mAtmColSign, 0 );
02827 for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
02828 lvi;
02829 lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
02830 lvi->enableCryptoCBs( false );
02831 }
02832 }
02833 }
02834 }
02835
02836 static void showExportError( QWidget * w, const GpgME::Error & err ) {
02837 assert( err );
02838 const QString msg = i18n("<qt><p>An error occurred while trying to export "
02839 "the key from the backend:</p>"
02840 "<p><b>%1</b></p></qt>")
02841 .arg( QString::fromLocal8Bit( err.asString() ) );
02842 KMessageBox::error( w, msg, i18n("Key Export Failed") );
02843 }
02844
02845
02846
02847 void KMComposeWin::slotInsertMyPublicKey()
02848 {
02849
02850 mFingerprint =
02851 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() ).pgpEncryptionKey();
02852 if ( !mFingerprint.isEmpty() )
02853 startPublicKeyExport();
02854 }
02855
02856 void KMComposeWin::startPublicKeyExport() {
02857 if ( mFingerprint.isEmpty() || !Kleo::CryptoBackendFactory::instance()->openpgp() )
02858 return;
02859 Kleo::ExportJob * job = Kleo::CryptoBackendFactory::instance()->openpgp()->publicKeyExportJob( true );
02860 assert( job );
02861
02862 connect( job, SIGNAL(result(const GpgME::Error&,const QByteArray&)),
02863 this, SLOT(slotPublicKeyExportResult(const GpgME::Error&,const QByteArray&)) );
02864
02865 const GpgME::Error err = job->start( mFingerprint );
02866 if ( err )
02867 showExportError( this, err );
02868 else
02869 (void)new Kleo::ProgressDialog( job, i18n("Exporting key..."), this );
02870 }
02871
02872 void KMComposeWin::slotPublicKeyExportResult( const GpgME::Error & err, const QByteArray & keydata ) {
02873 if ( err ) {
02874 showExportError( this, err );
02875 return;
02876 }
02877
02878
02879 KMMessagePart * msgPart = new KMMessagePart();
02880 msgPart->setName( i18n("OpenPGP key 0x%1").arg( mFingerprint ) );
02881 msgPart->setTypeStr("application");
02882 msgPart->setSubtypeStr("pgp-keys");
02883 QValueList<int> dummy;
02884 msgPart->setBodyAndGuessCte(keydata, dummy, false);
02885 msgPart->setContentDisposition( "attachment;\n\tfilename=0x" + QCString( mFingerprint.latin1() ) + ".asc" );
02886
02887
02888 addAttach(msgPart);
02889 rethinkFields();
02890 }
02891
02892
02893 void KMComposeWin::slotInsertPublicKey()
02894 {
02895 Kleo::KeySelectionDialog dlg( i18n("Attach Public OpenPGP Key"),
02896 i18n("Select the public key which should "
02897 "be attached."),
02898 std::vector<GpgME::Key>(),
02899 Kleo::KeySelectionDialog::PublicKeys|Kleo::KeySelectionDialog::OpenPGPKeys,
02900 false ,
02901 false ,
02902 this, "attach public key selection dialog" );
02903 if ( dlg.exec() != QDialog::Accepted )
02904 return;
02905
02906 mFingerprint = dlg.fingerprint();
02907 startPublicKeyExport();
02908 }
02909
02910
02911
02912 void KMComposeWin::slotAttachPopupMenu(QListViewItem *, const QPoint &, int)
02913 {
02914 if (!mAttachMenu)
02915 {
02916 mAttachMenu = new QPopupMenu(this);
02917
02918 mOpenId = mAttachMenu->insertItem(i18n("to open", "Open"), this,
02919 SLOT(slotAttachOpen()));
02920 mOpenWithId = mAttachMenu->insertItem(i18n("Open with..."), this,
02921 SLOT(slotAttachOpenWith()));
02922 mViewId = mAttachMenu->insertItem(i18n("to view", "View"), this,
02923 SLOT(slotAttachView()));
02924 mRemoveId = mAttachMenu->insertItem(i18n("Remove"), this, SLOT(slotAttachRemove()));
02925 mSaveAsId = mAttachMenu->insertItem( SmallIconSet("filesaveas"), i18n("Save As..."), this,
02926 SLOT( slotAttachSave() ) );
02927 mPropertiesId = mAttachMenu->insertItem( i18n("Properties"), this,
02928 SLOT( slotAttachProperties() ) );
02929 mAttachMenu->insertSeparator();
02930 mAttachMenu->insertItem(i18n("Add Attachment..."), this, SLOT(slotAttachFile()));
02931 }
02932
02933 int selectedCount = 0;
02934 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it ) {
02935 if ( (*it)->isSelected() ) {
02936 ++selectedCount;
02937 }
02938 }
02939
02940 mAttachMenu->setItemEnabled( mOpenId, selectedCount > 0 );
02941 mAttachMenu->setItemEnabled( mViewId, selectedCount > 0 );
02942 mAttachMenu->setItemEnabled( mRemoveId, selectedCount > 0 );
02943 mAttachMenu->setItemEnabled( mSaveAsId, selectedCount == 1 );
02944 mAttachMenu->setItemEnabled( mPropertiesId, selectedCount == 1 );
02945
02946 mAttachMenu->popup(QCursor::pos());
02947 }
02948
02949
02950 int KMComposeWin::currentAttachmentNum()
02951 {
02952 int i = 0;
02953 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i )
02954 if ( *it == mAtmListView->currentItem() )
02955 return i;
02956 return -1;
02957 }
02958
02959
02960 void KMComposeWin::slotAttachProperties()
02961 {
02962 int idx = currentAttachmentNum();
02963
02964 if (idx < 0) return;
02965
02966 KMMessagePart* msgPart = mAtmList.at(idx);
02967 msgPart->setCharset(mCharset);
02968
02969 KMMsgPartDialogCompat dlg(mMainWidget);
02970 dlg.setMsgPart(msgPart);
02971 KMAtmListViewItem* listItem = (KMAtmListViewItem*)(mAtmItemList.at(idx));
02972 if( canSignEncryptAttachments() && listItem ) {
02973 dlg.setCanSign( true );
02974 dlg.setCanEncrypt( true );
02975 dlg.setSigned( listItem->isSign() );
02976 dlg.setEncrypted( listItem->isEncrypt() );
02977 } else {
02978 dlg.setCanSign( false );
02979 dlg.setCanEncrypt( false );
02980 }
02981 if (dlg.exec())
02982 {
02983 mAtmModified = TRUE;
02984
02985 if( listItem ) {
02986 msgPartToItem(msgPart, listItem);
02987 if( canSignEncryptAttachments() ) {
02988 listItem->setSign( dlg.isSigned() );
02989 listItem->setEncrypt( dlg.isEncrypted() );
02990 }
02991 }
02992 }
02993 if (msgPart->typeStr().lower() != "text") msgPart->setCharset(QCString());
02994 }
02995
02996
02997 void KMComposeWin::compressAttach( int idx )
02998 {
02999 if (idx < 0) return;
03000
03001 unsigned int i;
03002 for ( i = 0; i < mAtmItemList.count(); ++i )
03003 if ( mAtmItemList.at( i )->itemPos() == idx )
03004 break;
03005
03006 if ( i > mAtmItemList.count() )
03007 return;
03008
03009 KMMessagePart* msgPart;
03010 msgPart = mAtmList.at( i );
03011 QByteArray array;
03012 QBuffer dev( array );
03013 KZip zip( &dev );
03014 QByteArray decoded = msgPart->bodyDecodedBinary();
03015 if ( ! zip.open( IO_WriteOnly ) ) {
03016 KMessageBox::sorry(0, i18n("KMail could not compress the file.") );
03017 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
03018 return;
03019 }
03020
03021 zip.setCompression( KZip::DeflateCompression );
03022 if ( ! zip.writeFile( msgPart->name(), "", "", decoded.size(),
03023 decoded.data() ) ) {
03024 KMessageBox::sorry(0, i18n("KMail could not compress the file.") );
03025 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
03026 return;
03027 }
03028 zip.close();
03029 if ( array.size() >= decoded.size() ) {
03030 if ( KMessageBox::questionYesNo( this, i18n("The compressed file is larger "
03031 "than the original. Do you want to keep the original one?" ), QString::null, i18n("Keep"), i18n("Compress") )
03032 == KMessageBox::Yes ) {
03033 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
03034 return;
03035 }
03036 }
03037 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setUncompressedCodec(
03038 msgPart->cteStr() );
03039
03040 msgPart->setCteStr( "base64" );
03041 msgPart->setBodyEncodedBinary( array );
03042 QString name = msgPart->name() + ".zip";
03043
03044 msgPart->setName( name );
03045
03046 QCString cDisp = "attachment;";
03047 QCString encoding = KMMsgBase::autoDetectCharset( msgPart->charset(),
03048 KMMessage::preferredCharsets(), name );
03049 kdDebug(5006) << "encoding: " << encoding << endl;
03050 if ( encoding.isEmpty() ) encoding = "utf-8";
03051 kdDebug(5006) << "encoding after: " << encoding << endl;
03052 QCString encName;
03053 if ( GlobalSettings::self()->outlookCompatibleAttachments() )
03054 encName = KMMsgBase::encodeRFC2047String( name, encoding );
03055 else
03056 encName = KMMsgBase::encodeRFC2231String( name, encoding );
03057
03058 cDisp += "\n\tfilename";
03059 if ( name != QString( encName ) )
03060 cDisp += "*=" + encName;
03061 else
03062 cDisp += "=\"" + encName + '"';
03063 msgPart->setContentDisposition( cDisp );
03064
03065 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setUncompressedMimeType(
03066 msgPart->typeStr(), msgPart->subtypeStr() );
03067 msgPart->setTypeStr( "application" );
03068 msgPart->setSubtypeStr( "x-zip" );
03069
03070 KMAtmListViewItem* listItem = static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) );
03071 msgPartToItem( msgPart, listItem, false );
03072 }
03073
03074
03075
03076 void KMComposeWin::uncompressAttach( int idx )
03077 {
03078 if (idx < 0) return;
03079
03080 unsigned int i;
03081 for ( i = 0; i < mAtmItemList.count(); ++i )
03082 if ( mAtmItemList.at( i )->itemPos() == idx )
03083 break;
03084
03085 if ( i > mAtmItemList.count() )
03086 return;
03087
03088 KMMessagePart* msgPart;
03089 msgPart = mAtmList.at( i );
03090
03091 QBuffer dev( msgPart->bodyDecodedBinary() );
03092 KZip zip( &dev );
03093 QByteArray decoded;
03094
03095 decoded = msgPart->bodyDecodedBinary();
03096 if ( ! zip.open( IO_ReadOnly ) ) {
03097 KMessageBox::sorry(0, i18n("KMail could not uncompress the file.") );
03098 static_cast<KMAtmListViewItem *>( mAtmItemList.at( i ) )->setCompress( true );
03099 return;
03100 }
03101 const KArchiveDirectory *dir = zip.directory();
03102
03103 KZipFileEntry *entry;
03104 if ( dir->entries().count() != 1 ) {
03105 KMessageBox::sorry(0, i18n("KMail could not uncompress the file.") );
03106 static_cast<KMAtmListViewItem *>( mAtmItemList.at( i ) )->setCompress( true );
03107 return;
03108 }
03109 entry = (KZipFileEntry*)dir->entry( dir->entries()[0] );
03110
03111 msgPart->setCteStr(
03112 static_cast<KMAtmListViewItem*>( mAtmItemList.at(i) )->uncompressedCodec() );
03113
03114 msgPart->setBodyEncodedBinary( entry->data() );
03115 QString name = entry->name();
03116 msgPart->setName( name );
03117
03118 zip.close();
03119
03120 QCString cDisp = "attachment;";
03121 QCString encoding = KMMsgBase::autoDetectCharset( msgPart->charset(),
03122 KMMessage::preferredCharsets(), name );
03123 if ( encoding.isEmpty() ) encoding = "utf-8";
03124
03125 QCString encName;
03126 if ( GlobalSettings::self()->outlookCompatibleAttachments() )
03127 encName = KMMsgBase::encodeRFC2047String( name, encoding );
03128 else
03129 encName = KMMsgBase::encodeRFC2231String( name, encoding );
03130
03131 cDisp += "\n\tfilename";
03132 if ( name != QString( encName ) )
03133 cDisp += "*=" + encName;
03134 else
03135 cDisp += "=\"" + encName + '"';
03136 msgPart->setContentDisposition( cDisp );
03137
03138 QCString type, subtype;
03139 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->uncompressedMimeType( type,
03140 subtype );
03141
03142 msgPart->setTypeStr( type );
03143 msgPart->setSubtypeStr( subtype );
03144
03145 KMAtmListViewItem* listItem = static_cast<KMAtmListViewItem*>(mAtmItemList.at( i ));
03146 msgPartToItem( msgPart, listItem, false );
03147 }
03148
03149
03150
03151 void KMComposeWin::slotAttachView()
03152 {
03153 int i = 0;
03154 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
03155 if ( (*it)->isSelected() ) {
03156 viewAttach( i );
03157 }
03158 }
03159 }
03160
03161 void KMComposeWin::slotAttachOpen()
03162 {
03163 int i = 0;
03164 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
03165 if ( (*it)->isSelected() ) {
03166 openAttach( i, false );
03167 }
03168 }
03169 }
03170
03171
03172 void KMComposeWin::slotAttachOpenWith()
03173 {
03174 int i = 0;
03175 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
03176 if ( (*it)->isSelected() ) {
03177 openAttach( i, true );
03178 }
03179 }
03180 }
03181
03182
03183 bool KMComposeWin::inlineSigningEncryptionSelected() {
03184 if ( !mSignAction->isChecked() && !mEncryptAction->isChecked() )
03185 return false;
03186 return cryptoMessageFormat() == Kleo::InlineOpenPGPFormat;
03187 }
03188
03189
03190 void KMComposeWin::viewAttach( int index )
03191 {
03192 QString pname;
03193 KMMessagePart* msgPart;
03194 msgPart = mAtmList.at(index);
03195 pname = msgPart->name().stripWhiteSpace();
03196 if (pname.isEmpty()) pname=msgPart->contentDescription();
03197 if (pname.isEmpty()) pname="unnamed";
03198
03199 KTempFile* atmTempFile = new KTempFile();
03200 mAtmTempList.append( atmTempFile );
03201 atmTempFile->setAutoDelete( true );
03202 KPIM::kByteArrayToFile(msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
03203 false);
03204 KMReaderMainWin *win = new KMReaderMainWin(msgPart, false,
03205 atmTempFile->name(), pname, mCharset );
03206 win->show();
03207 }
03208
03209
03210 void KMComposeWin::openAttach( int index, bool with )
03211 {
03212 KMMessagePart* msgPart = mAtmList.at(index);
03213 const QString contentTypeStr =
03214 ( msgPart->typeStr() + '/' + msgPart->subtypeStr() ).lower();
03215
03216 KMimeType::Ptr mimetype;
03217 mimetype = KMimeType::mimeType( contentTypeStr );
03218
03219 KTempFile* atmTempFile = new KTempFile();
03220 mAtmTempList.append( atmTempFile );
03221 const bool autoDelete = true;
03222 atmTempFile->setAutoDelete( autoDelete );
03223
03224 KURL url;
03225 url.setPath( atmTempFile->name() );
03226
03227 KPIM::kByteArrayToFile( msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
03228 false );
03229 if ( ::chmod( QFile::encodeName( atmTempFile->name() ), S_IRUSR ) != 0) {
03230 QFile::remove(url.path());
03231 return;
03232 }
03233
03234 KService::Ptr offer =
03235 KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
03236
03237 if ( with || !offer || mimetype->name() == "application/octet-stream" ) {
03238 if ( ( !KRun::displayOpenWithDialog( url, autoDelete ) ) && autoDelete ) {
03239 QFile::remove(url.path());
03240 }
03241 }
03242 else {
03243 if ( ( !KRun::run( *offer, url, autoDelete ) ) && autoDelete ) {
03244 QFile::remove( url.path() );
03245 }
03246 }
03247 }
03248
03249
03250 void KMComposeWin::slotAttachSave()
03251 {
03252 KMMessagePart* msgPart;
03253 QString fileName, pname;
03254 int idx = currentAttachmentNum();
03255
03256 if (idx < 0) return;
03257
03258 msgPart = mAtmList.at(idx);
03259 pname = msgPart->name();
03260 if (pname.isEmpty()) pname="unnamed";
03261
03262 KURL url = KFileDialog::getSaveURL(QString::null, QString::null, 0, i18n("Save Attachment As"));
03263
03264 if( url.isEmpty() )
03265 return;
03266
03267 kmkernel->byteArrayToRemoteFile(msgPart->bodyDecodedBinary(), url);
03268 }
03269
03270
03271
03272 void KMComposeWin::slotAttachRemove()
03273 {
03274 bool attachmentRemoved = false;
03275 int i = 0;
03276 for ( QPtrListIterator<QListViewItem> it(mAtmItemList); *it; ) {
03277 if ( (*it)->isSelected() ) {
03278 removeAttach( i );
03279 attachmentRemoved = true;
03280 }
03281 else {
03282 ++it;
03283 ++i;
03284 }
03285 }
03286
03287 if ( attachmentRemoved ) {
03288 setModified( true );
03289 slotUpdateAttachActions();
03290 }
03291 }
03292
03293
03294 void KMComposeWin::slotFind()
03295 {
03296 mEditor->search();
03297 }
03298
03299 void KMComposeWin::slotSearchAgain()
03300 {
03301 mEditor->repeatSearch();
03302 }
03303
03304
03305 void KMComposeWin::slotReplace()
03306 {
03307 mEditor->replace();
03308 }
03309
03310
03311 void KMComposeWin::slotUpdateFont()
03312 {
03313 kdDebug() << "KMComposeWin::slotUpdateFont " << endl;
03314 if ( ! mFixedFontAction ) {
03315 return;
03316 }
03317 mEditor->setFont( mFixedFontAction->isChecked() ? mFixedFont : mBodyFont );
03318 }
03319
03320 QString KMComposeWin::quotePrefixName() const
03321 {
03322 if ( !msg() )
03323 return QString::null;
03324
03325 int languageNr = GlobalSettings::self()->replyCurrentLanguage();
03326 ReplyPhrases replyPhrases( QString::number(languageNr) );
03327 replyPhrases.readConfig();
03328 QString quotePrefix = msg()->formatString(
03329 replyPhrases.indentPrefix() );
03330
03331 quotePrefix = msg()->formatString(quotePrefix);
03332 return quotePrefix;
03333 }
03334
03335 void KMComposeWin::slotPasteAsQuotation()
03336 {
03337 if( mEditor->hasFocus() && msg() )
03338 {
03339 QString s = QApplication::clipboard()->text();
03340 if (!s.isEmpty())
03341 mEditor->insert(addQuotesToText(s));
03342 }
03343 }
03344
03345 void KMComposeWin::slotPasteAsAttachment()
03346 {
03347 KURL url( QApplication::clipboard()->text( QClipboard::Clipboard ) );
03348 if ( url.isValid() ) {
03349 addAttach(QApplication::clipboard()->text( QClipboard::Clipboard ) );
03350 return;
03351 }
03352
03353 if ( QApplication::clipboard()->image().isNull() ) {
03354 bool ok;
03355 QString attName = KInputDialog::getText( "KMail", i18n("Name of the attachment:"), QString::null, &ok, this );
03356 if ( !ok )
03357 return;
03358 KMMessagePart *msgPart = new KMMessagePart;
03359 msgPart->setName(attName);
03360 QValueList<int> dummy;
03361 msgPart->setBodyAndGuessCte(QCString(QApplication::clipboard()->text().latin1()), dummy,
03362 kmkernel->msgSender()->sendQuotedPrintable());
03363 addAttach(msgPart);
03364 }
03365 else
03366 addImageFromClipboard();
03367
03368 }
03369
03370 void KMComposeWin::slotAddQuotes()
03371 {
03372 if( mEditor->hasFocus() && msg() )
03373 {
03374
03375
03376
03377
03378 if ( mEditor->hasMarkedText() ) {
03379 QString s = mEditor->markedText();
03380 if(!s.isEmpty())
03381 mEditor->insert(addQuotesToText(s));
03382 } else {
03383 int l = mEditor->currentLine();
03384 int c = mEditor->currentColumn();
03385 QString s = mEditor->textLine(l);
03386 s.prepend(quotePrefixName());
03387 mEditor->insertLine(s,l);
03388 mEditor->removeLine(l+1);
03389 mEditor->setCursorPosition(l,c+2);
03390 }
03391 }
03392 }
03393
03394 QString KMComposeWin::addQuotesToText(const QString &inputText)
03395 {
03396 QString answer = QString( inputText );
03397 QString indentStr = quotePrefixName();
03398 answer.replace( '\n', '\n' + indentStr);
03399 answer.prepend( indentStr );
03400 answer += '\n';
03401 return KMMessage::smartQuote( answer, GlobalSettings::self()->lineWrapWidth() );
03402 }
03403
03404 QString KMComposeWin::removeQuotesFromText(const QString &inputText)
03405 {
03406 QString s = inputText;
03407
03408
03409 QString quotePrefix = '^' + quotePrefixName();
03410 QRegExp rx(quotePrefix);
03411 s.remove(rx);
03412
03413
03414 quotePrefix = '\n' + quotePrefixName();
03415 rx = quotePrefix;
03416 s.replace(rx, "\n");
03417
03418 return s;
03419 }
03420
03421 void KMComposeWin::slotRemoveQuotes()
03422 {
03423 if( mEditor->hasFocus() && msg() )
03424 {
03425
03426
03427
03428
03429 if ( mEditor->hasMarkedText() ) {
03430 QString s = mEditor->markedText();
03431 mEditor->insert(removeQuotesFromText(s));
03432 } else {
03433 int l = mEditor->currentLine();
03434 int c = mEditor->currentColumn();
03435 QString s = mEditor->textLine(l);
03436 mEditor->insertLine(removeQuotesFromText(s),l);
03437 mEditor->removeLine(l+1);
03438 mEditor->setCursorPosition(l,c-2);
03439 }
03440 }
03441 }
03442
03443
03444 void KMComposeWin::slotUndo()
03445 {
03446 QWidget* fw = focusWidget();
03447 if (!fw) return;
03448
03449 if ( ::qt_cast<KEdit*>(fw) )
03450 static_cast<QTextEdit*>(fw)->undo();
03451 else if (::qt_cast<QLineEdit*>(fw))
03452 static_cast<QLineEdit*>(fw)->undo();
03453 }
03454
03455 void KMComposeWin::slotRedo()
03456 {
03457 QWidget* fw = focusWidget();
03458 if (!fw) return;
03459
03460 if (::qt_cast<KEdit*>(fw))
03461 static_cast<KEdit*>(fw)->redo();
03462 else if (::qt_cast<QLineEdit*>(fw))
03463 static_cast<QLineEdit*>(fw)->redo();
03464 }
03465
03466
03467 void KMComposeWin::slotCut()
03468 {
03469 QWidget* fw = focusWidget();
03470 if (!fw) return;
03471
03472 if (::qt_cast<KEdit*>(fw))
03473 static_cast<KEdit*>(fw)->cut();
03474 else if (::qt_cast<QLineEdit*>(fw))
03475 static_cast<QLineEdit*>(fw)->cut();
03476 }
03477
03478
03479
03480 void KMComposeWin::slotCopy()
03481 {
03482 QWidget* fw = focusWidget();
03483 if (!fw) return;
03484
03485 #ifdef KeyPress
03486 #undef KeyPress
03487 #endif
03488
03489 QKeyEvent k(QEvent::KeyPress, Key_C , 0 , ControlButton);
03490 kapp->notify(fw, &k);
03491 }
03492
03493
03494
03495 void KMComposeWin::slotPaste()
03496 {
03497 QWidget* fw = focusWidget();
03498 if (!fw) return;
03499
03500 if ( ! QApplication::clipboard()->image().isNull() ) {
03501 addImageFromClipboard();
03502 }
03503 else {
03504
03505 #ifdef KeyPress
03506 #undef KeyPress
03507 #endif
03508
03509 QKeyEvent k(QEvent::KeyPress, Key_V , 0 , ControlButton);
03510 kapp->notify(fw, &k);
03511 }
03512
03513 }
03514
03515
03516
03517 void KMComposeWin::slotMarkAll()
03518 {
03519 QWidget* fw = focusWidget();
03520 if (!fw) return;
03521
03522 if (::qt_cast<QLineEdit*>(fw))
03523 static_cast<QLineEdit*>(fw)->selectAll();
03524 else if (::qt_cast<KEdit*>(fw))
03525 static_cast<KEdit*>(fw)->selectAll();
03526 }
03527
03528
03529
03530 void KMComposeWin::slotClose()
03531 {
03532 close(FALSE);
03533 }
03534
03535
03536
03537 void KMComposeWin::slotNewComposer()
03538 {
03539 KMComposeWin* win;
03540 KMMessage* msg = new KMMessage;
03541
03542 msg->initHeader();
03543 win = new KMComposeWin(msg);
03544 win->show();
03545 }
03546
03547
03548
03549 void KMComposeWin::slotNewMailReader()
03550 {
03551 KMMainWin *kmmwin = new KMMainWin(0);
03552 kmmwin->show();
03553
03554 }
03555
03556
03557
03558 void KMComposeWin::slotUpdWinTitle(const QString& text)
03559 {
03560 if (text.isEmpty())
03561 setCaption("("+i18n("unnamed")+")");
03562 else setCaption(text);
03563 }
03564
03565
03566
03567 void KMComposeWin::slotEncryptToggled(bool on)
03568 {
03569 setEncryption( on, true );
03570 }
03571
03572
03573
03574 void KMComposeWin::setEncryption( bool encrypt, bool setByUser )
03575 {
03576 if ( setByUser )
03577 setModified( true );
03578 if ( !mEncryptAction->isEnabled() )
03579 encrypt = false;
03580
03581
03582 else if ( encrypt && encryptToSelf() && !mLastIdentityHasEncryptionKey ) {
03583 if ( setByUser )
03584 KMessageBox::sorry( this,
03585 i18n("<qt><p>You have requested that messages be "
03586 "encrypted to yourself, but the currently selected "
03587 "identity does not define an (OpenPGP or S/MIME) "
03588 "encryption key to use for this.</p>"
03589 "<p>Please select the key(s) to use "
03590 "in the identity configuration.</p>"
03591 "</qt>"),
03592 i18n("Undefined Encryption Key") );
03593 encrypt = false;
03594 }
03595
03596
03597 mEncryptAction->setChecked( encrypt );
03598
03599
03600 if ( encrypt )
03601 mEncryptAction->setIcon("encrypted");
03602 else
03603 mEncryptAction->setIcon("decrypted");
03604
03605
03606 if ( canSignEncryptAttachments() ) {
03607 for ( KMAtmListViewItem* entry =
03608 static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
03609 entry;
03610 entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
03611 entry->setEncrypt( encrypt );
03612 }
03613 }
03614
03615
03616
03617 void KMComposeWin::slotSignToggled(bool on)
03618 {
03619 setSigning( on, true );
03620 }
03621
03622
03623
03624 void KMComposeWin::setSigning( bool sign, bool setByUser )
03625 {
03626 if ( setByUser )
03627 setModified( true );
03628 if ( !mSignAction->isEnabled() )
03629 sign = false;
03630
03631
03632 if ( sign && !mLastIdentityHasSigningKey ) {
03633 if ( setByUser )
03634 KMessageBox::sorry( this,
03635 i18n("<qt><p>In order to be able to sign "
03636 "this message you first have to "
03637 "define the (OpenPGP or S/MIME) signing key "
03638 "to use.</p>"
03639 "<p>Please select the key to use "
03640 "in the identity configuration.</p>"
03641 "</qt>"),
03642 i18n("Undefined Signing Key") );
03643 sign = false;
03644 }
03645
03646
03647 mSignAction->setChecked( sign );
03648
03649
03650 if ( canSignEncryptAttachments() ) {
03651 for ( KMAtmListViewItem* entry =
03652 static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
03653 entry;
03654 entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
03655 entry->setSign( sign );
03656 }
03657 }
03658
03659
03660
03661 void KMComposeWin::slotWordWrapToggled(bool on)
03662 {
03663 if (on)
03664 {
03665 mEditor->setWordWrap( QTextEdit::FixedColumnWidth );
03666 mEditor->setWrapColumnOrWidth( GlobalSettings::self()->lineWrapWidth() );
03667 }
03668 else
03669 {
03670 mEditor->setWordWrap( QTextEdit::NoWrap );
03671 }
03672 }
03673
03674
03675
03676 void KMComposeWin::slotPrint()
03677 {
03678 mMessageWasModified = isModified();
03679 connect( this, SIGNAL( applyChangesDone( bool ) ),
03680 this, SLOT( slotContinuePrint( bool ) ) );
03681 applyChanges( true );
03682 }
03683
03684 void KMComposeWin::slotContinuePrint( bool rc )
03685 {
03686 disconnect( this, SIGNAL( applyChangesDone( bool ) ),
03687 this, SLOT( slotContinuePrint( bool ) ) );
03688
03689 if( rc ) {
03690 if ( mComposedMessages.isEmpty() ) {
03691 kdDebug(5006) << "Composing the message failed." << endl;
03692 return;
03693 }
03694 KMCommand *command = new KMPrintCommand( this, mComposedMessages.first() );
03695 command->start();
03696 setModified( mMessageWasModified );
03697 }
03698 }
03699
03700
03701 bool KMComposeWin::validateAddresses( QWidget * parent, const QString & addresses )
03702 {
03703 QString brokenAddress;
03704 KPIM::EmailParseResult errorCode = KMMessage::isValidEmailAddressList( KMMessage::expandAliases( addresses ), brokenAddress );
03705 if ( !( errorCode == KPIM::AddressOk || errorCode == KPIM::AddressEmpty ) ) {
03706 QString errorMsg( "<qt><p><b>" + brokenAddress +
03707 "</b></p><p>" + KPIM::emailParseResultToString( errorCode ) +
03708 "</p></qt>" );
03709 KMessageBox::sorry( parent, errorMsg, i18n("Invalid Email Address") );
03710 return false;
03711 }
03712 return true;
03713 }
03714
03715
03716 void KMComposeWin::doSend( KMail::MessageSender::SendMethod method, bool saveInDrafts)
03717 {
03718 if ( method != KMail::MessageSender::SendLater && kmkernel->isOffline() ) {
03719 KMessageBox::information( this,
03720 i18n("KMail is currently in offline mode,"
03721 "your messages will be kept in the outbox until you go online."),
03722 i18n("Online/Offline"), "kmailIsOffline" );
03723 mSendMethod = KMail::MessageSender::SendLater;
03724 } else {
03725 mSendMethod = method;
03726 }
03727 mSaveInDrafts = saveInDrafts;
03728
03729 if (!saveInDrafts)
03730 {
03731 if ( KPIM::getFirstEmailAddress( from() ).isEmpty() ) {
03732 if ( !( mShowHeaders & HDR_FROM ) ) {
03733 mShowHeaders |= HDR_FROM;
03734 rethinkFields( false );
03735 }
03736 mEdtFrom->setFocus();
03737 KMessageBox::sorry( this,
03738 i18n("You must enter your email address in the "
03739 "From: field. You should also set your email "
03740 "address for all identities, so that you do "
03741 "not have to enter it for each message.") );
03742 return;
03743 }
03744 if (to().isEmpty() && cc().isEmpty() && bcc().isEmpty())
03745 {
03746 if ( mEdtTo ) mEdtTo->setFocus();
03747 KMessageBox::information( this,
03748 i18n("You must specify at least one receiver,"
03749 "either in the To: field or as CC or as BCC.") );
03750 return;
03751 }
03752
03753
03754 if ( !validateAddresses( this, to().stripWhiteSpace() ) ) {
03755 return;
03756 }
03757
03758 if ( !validateAddresses( this, cc().stripWhiteSpace() ) ) {
03759 return;
03760 }
03761
03762 if ( !validateAddresses( this, bcc().stripWhiteSpace() ) ) {
03763 return;
03764 }
03765
03766 if (subject().isEmpty())
03767 {
03768 mEdtSubject->setFocus();
03769 int rc =
03770 KMessageBox::questionYesNo( this,
03771 i18n("You did not specify a subject. "
03772 "Send message anyway?"),
03773 i18n("No Subject Specified"),
03774 i18n("S&end as Is"),
03775 i18n("&Specify the Subject"),
03776 "no_subject_specified" );
03777 if( rc == KMessageBox::No )
03778 {
03779 return;
03780 }
03781 }
03782
03783 if ( userForgotAttachment() )
03784 return;
03785 }
03786
03787 KCursorSaver busy(KBusyPtr::busy());
03788 mMsg->setDateToday();
03789
03790
03791
03792
03793
03794
03795 QString hf = mMsg->headerField("X-KMail-Transport");
03796 if ((mTransport->currentText() != mTransport->text(0)) ||
03797 (!hf.isEmpty() && (hf != mTransport->text(0))))
03798 mMsg->setHeaderField("X-KMail-Transport", mTransport->currentText());
03799
03800 mDisableBreaking = saveInDrafts;
03801
03802 const bool neverEncrypt = ( saveInDrafts && GlobalSettings::self()->neverEncryptDrafts() )
03803 || mSigningAndEncryptionExplicitlyDisabled;
03804 connect( this, SIGNAL( applyChangesDone( bool ) ),
03805 SLOT( slotContinueDoSend( bool ) ) );
03806
03807 if ( mEditor->textFormat() == Qt::RichText )
03808 mMsg->setHeaderField( "X-KMail-Markup", "true" );
03809 else
03810 mMsg->removeHeaderField( "X-KMail-Markup" );
03811 if ( mEditor->textFormat() == Qt::RichText && inlineSigningEncryptionSelected() ) {
03812 QString keepBtnText = mEncryptAction->isChecked() ?
03813 mSignAction->isChecked() ? i18n( "&Keep markup, do not sign/encrypt" )
03814 : i18n( "&Keep markup, do not encrypt" )
03815 : i18n( "&Keep markup, do not sign" );
03816 QString yesBtnText = mEncryptAction->isChecked() ?
03817 mSignAction->isChecked() ? i18n("Sign/Encrypt (delete markup)")
03818 : i18n( "Encrypt (delete markup)" )
03819 : i18n( "Sign (delete markup)" );
03820 int ret = KMessageBox::warningYesNoCancel(this,
03821 i18n("<qt><p>Inline signing/encrypting of HTML messages is not possible;</p>"
03822 "<p>do you want to delete your markup?</p></qt>"),
03823 i18n("Sign/Encrypt Message?"),
03824 KGuiItem( yesBtnText ),
03825 KGuiItem( keepBtnText ) );
03826 if ( KMessageBox::Cancel == ret )
03827 return;
03828 if ( KMessageBox::No == ret ) {
03829 mEncryptAction->setChecked(false);
03830 mSignAction->setChecked(false);
03831 }
03832 else {
03833 toggleMarkup(false);
03834 }
03835 }
03836
03837 kdDebug(5006) << "KMComposeWin::doSend() - calling applyChanges()"
03838 << endl;
03839 applyChanges( neverEncrypt );
03840 }
03841
03842 void KMComposeWin::slotContinueDoSend( bool sentOk )
03843 {
03844 kdDebug(5006) << "KMComposeWin::slotContinueDoSend( " << sentOk << " )"
03845 << endl;
03846 disconnect( this, SIGNAL( applyChangesDone( bool ) ),
03847 this, SLOT( slotContinueDoSend( bool ) ) );
03848
03849 if ( !sentOk ) {
03850 mDisableBreaking = false;
03851 return;
03852 }
03853
03854 for ( QValueVector<KMMessage*>::iterator it = mComposedMessages.begin() ; it != mComposedMessages.end() ; ++it ) {
03855
03856
03857 (*it)->cleanupHeader();
03858
03859
03860 (*it)->setComplete( true );
03861
03862 if (mSaveInDrafts) {
03863 KMFolder* draftsFolder = 0, *imapDraftsFolder = 0;
03864
03865 if ( !(*it)->drafts().isEmpty() ) {
03866 draftsFolder = kmkernel->folderMgr()->findIdString( (*it)->drafts() );
03867 if ( draftsFolder == 0 )
03868
03869
03870 draftsFolder = kmkernel->dimapFolderMgr()->findIdString( (*it)->drafts() );
03871 if ( draftsFolder == 0 )
03872 imapDraftsFolder = kmkernel->imapFolderMgr()->findIdString( (*it)->drafts() );
03873 if ( !draftsFolder && !imapDraftsFolder ) {
03874 const KPIM::Identity & id = kmkernel->identityManager()
03875 ->identityForUoidOrDefault( (*it)->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt() );
03876 KMessageBox::information(0, i18n("The custom drafts folder for identity "
03877 "\"%1\" does not exist (anymore); "
03878 "therefore, the default drafts folder "
03879 "will be used.")
03880 .arg( id.identityName() ) );
03881 }
03882 }
03883 if (imapDraftsFolder && imapDraftsFolder->noContent())
03884 imapDraftsFolder = 0;
03885
03886 if ( draftsFolder == 0 ) {
03887 draftsFolder = kmkernel->draftsFolder();
03888 } else {
03889 draftsFolder->open();
03890 }
03891 kdDebug(5006) << "saveindrafts: drafts=" << draftsFolder->name() << endl;
03892 if (imapDraftsFolder)
03893 kdDebug(5006) << "saveindrafts: imapdrafts="
03894 << imapDraftsFolder->name() << endl;
03895
03896 sentOk = !(draftsFolder->addMsg((*it)));
03897
03898
03899 draftsFolder->unGetMsg(draftsFolder->count() - 1);
03900 (*it) = draftsFolder->getMsg(draftsFolder->count() - 1);
03901
03902 if (imapDraftsFolder) {
03903
03904 imapDraftsFolder->moveMsg((*it));
03905 (static_cast<KMFolderImap*>(imapDraftsFolder->storage()))->getFolder();
03906 }
03907
03908 } else {
03909 (*it)->setTo( KMMessage::expandAliases( to() ));
03910 (*it)->setCc( KMMessage::expandAliases( cc() ));
03911 if( !mComposer->originalBCC().isEmpty() )
03912 (*it)->setBcc( KMMessage::expandAliases( mComposer->originalBCC() ));
03913 QString recips = (*it)->headerField( "X-KMail-Recipients" );
03914 if( !recips.isEmpty() ) {
03915 (*it)->setHeaderField( "X-KMail-Recipients", KMMessage::expandAliases( recips ), KMMessage::Address );
03916 }
03917 (*it)->cleanupHeader();
03918 sentOk = kmkernel->msgSender()->send((*it), mSendMethod);
03919 }
03920
03921 if (!sentOk)
03922 return;
03923
03924 *it = 0;
03925 }
03926
03927 RecentAddresses::self( KMKernel::config() )->add( bcc() );
03928 RecentAddresses::self( KMKernel::config() )->add( cc() );
03929 RecentAddresses::self( KMKernel::config() )->add( to() );
03930
03931 setModified( false );
03932 mAutoDeleteMsg = FALSE;
03933 mFolder = 0;
03934 cleanupAutoSave();
03935 close();
03936 return;
03937 }
03938
03939
03940
03941
03942 void KMComposeWin::slotSendLater()
03943 {
03944 if ( mEditor->checkExternalEditorFinished() )
03945 doSend( KMail::MessageSender::SendLater );
03946 }
03947
03948
03949
03950 void KMComposeWin::slotSaveDraft() {
03951 if ( mEditor->checkExternalEditorFinished() )
03952 doSend( KMail::MessageSender::SendLater, true );
03953 }
03954
03955
03956
03957 void KMComposeWin::slotSendNowVia( int item )
03958 {
03959 QStringList availTransports= KMail::TransportManager::transportNames();
03960 QString customTransport = availTransports[ item ];
03961
03962 mTransport->setCurrentText( customTransport );
03963 slotSendNow();
03964 }
03965
03966
03967 void KMComposeWin::slotSendLaterVia( int item )
03968 {
03969 QStringList availTransports= KMail::TransportManager::transportNames();
03970 QString customTransport = availTransports[ item ];
03971
03972 mTransport->setCurrentText( customTransport );
03973 slotSendLater();
03974 }
03975
03976
03977
03978 void KMComposeWin::slotSendNow() {
03979 if ( !mEditor->checkExternalEditorFinished() )
03980 return;
03981 if ( GlobalSettings::self()->confirmBeforeSend() )
03982 {
03983 int rc = KMessageBox::warningYesNoCancel( mMainWidget,
03984 i18n("About to send email..."),
03985 i18n("Send Confirmation"),
03986 i18n("&Send Now"),
03987 i18n("Send &Later") );
03988
03989 if ( rc == KMessageBox::Yes )
03990 doSend( KMail::MessageSender::SendImmediate );
03991 else if ( rc == KMessageBox::No )
03992 doSend( KMail::MessageSender::SendLater );
03993 }
03994 else
03995 doSend( KMail::MessageSender::SendImmediate );
03996 }
03997
03998
03999
04000 void KMComposeWin::slotAppendSignature()
04001 {
04002 bool mod = mEditor->isModified();
04003
04004 const KPIM::Identity & ident =
04005 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
04006 mOldSigText = ident.signatureText();
04007 if( !mOldSigText.isEmpty() )
04008 {
04009 mEditor->append(mOldSigText);
04010 mEditor->setModified(mod);
04011 mEditor->setContentsPos( 0, 0 );
04012 mEditor->sync();
04013 }
04014 }
04015
04016
04017
04018 void KMComposeWin::slotHelp()
04019 {
04020 kapp->invokeHelp();
04021 }
04022
04023
04024 void KMComposeWin::slotCleanSpace()
04025 {
04026
04027
04028
04029
04030
04031
04032
04033
04034 QString s;
04035 if ( mEditor->hasMarkedText() ) {
04036 s = mEditor->markedText();
04037 if( s.isEmpty() )
04038 return;
04039 } else {
04040 s = mEditor->text();
04041 }
04042
04043
04044 QString sig;
04045 bool restore = false;
04046 const KPIM::Identity & ident =
04047 kmkernel->identityManager()->identityForUoid( mId );
04048 if ( !ident.isNull() ) {
04049 sig = ident.signatureText();
04050 if( !sig.isEmpty() ) {
04051 if( s.endsWith( sig ) ) {
04052 s.truncate( s.length() - sig.length() );
04053 restore = true;
04054 }
04055 }
04056 }
04057
04058
04059 QRegExp squeeze( "[\t ]+" );
04060 s.replace( squeeze, QChar( ' ' ) );
04061
04062
04063 QRegExp trailing( "\\s+$" );
04064 s.replace( trailing, QChar( '\n' ) );
04065
04066
04067 QRegExp singleSpace( "[\n]{2,}" );
04068 s.replace( singleSpace, QChar( '\n' ) );
04069
04070
04071 if ( restore )
04072 s.append( sig );
04073
04074
04075
04076
04077
04078
04079
04080
04081 if ( !mEditor->hasMarkedText() )
04082 mEditor->clear();
04083 mEditor->insert( s );
04084 }
04085
04086
04087 void KMComposeWin::slotToggleMarkup()
04088 {
04089 if ( markupAction->isChecked() ) {
04090 mHtmlMarkup = true;
04091 toolBar("htmlToolBar")->show();
04092
04093 fontChanged( mEditor->currentFont() );
04094 mSaveFont = mEditor->currentFont();
04095 }
04096 else
04097 toggleMarkup(false);
04098
04099 }
04100
04101 void KMComposeWin::toggleMarkup(bool markup)
04102 {
04103 if ( markup ) {
04104 if ( !mUseHTMLEditor ) {
04105 kdDebug(5006) << "setting RichText editor" << endl;
04106 mUseHTMLEditor = true;
04107 mHtmlMarkup = true;
04108
04109
04110 int paraFrom, indexFrom, paraTo, indexTo;
04111 mEditor->getSelection ( ¶From, &indexFrom, ¶To, &indexTo);
04112 mEditor->selectAll();
04113
04114 bool _bold = textBoldAction->isChecked();
04115 bool _italic = textItalicAction->isChecked();
04116 mEditor->setColor(QColor(0,0,0));
04117 textBoldAction->setChecked(_bold);
04118 textItalicAction->setChecked(_italic);
04119 mEditor->setSelection ( paraFrom, indexFrom, paraTo, indexTo);
04120
04121 mEditor->setTextFormat(Qt::RichText);
04122 mEditor->setModified(true);
04123 markupAction->setChecked(true);
04124 toolBar( "htmlToolBar" )->show();
04125 mEditor->deleteAutoSpellChecking();
04126 mAutoSpellCheckingAction->setChecked(false);
04127 slotAutoSpellCheckingToggled(false);
04128 }
04129 } else {
04130 kdDebug(5006) << "setting PlainText editor" << endl;
04131 mHtmlMarkup = false;
04132 toolBar("htmlToolBar")->hide();
04133 if ( mUseHTMLEditor ) {
04134 mUseHTMLEditor = false;
04135 mEditor->setTextFormat(Qt::PlainText);
04136 QString text = mEditor->text();
04137 mEditor->setText(text);
04138 mEditor->setModified(true);
04139 slotAutoSpellCheckingToggled(true);
04140 }
04141 }
04142 }
04143
04144 void KMComposeWin::htmlToolBarVisibilityChanged( bool visible )
04145 {
04146
04147 if ( !visible ) {
04148 markupAction->setChecked( false );
04149 toggleMarkup( false );
04150 }
04151 }
04152
04153 void KMComposeWin::slotSubjectTextSpellChecked()
04154 {
04155 mSubjectTextWasSpellChecked = true;
04156 }
04157
04158
04159 void KMComposeWin::slotAutoSpellCheckingToggled( bool on )
04160 {
04161 if ( mEditor->autoSpellChecking(on) == -1 ) {
04162 mAutoSpellCheckingAction->setChecked(false);
04163 }
04164
04165 QString temp;
04166 if ( on )
04167 temp = i18n( "Spellcheck: on" );
04168 else
04169 temp = i18n( "Spellcheck: off" );
04170 statusBar()->changeItem( temp, 3 );
04171 }
04172
04173 void KMComposeWin::slotSpellcheck()
04174 {
04175 if (mSpellCheckInProgress) return;
04176 mSubjectTextWasSpellChecked = false;
04177 mSpellCheckInProgress=TRUE;
04178
04179
04180
04181
04182
04183 mEditor->spellcheck();
04184 }
04185
04186 void KMComposeWin::polish()
04187 {
04188
04189 markupAction->setChecked(mHtmlMarkup);
04190 if (mHtmlMarkup)
04191 toolBar("htmlToolBar")->show();
04192 else
04193 toolBar("htmlToolBar")->hide();
04194 KMail::Composer::polish();
04195 }
04196
04197
04198 void KMComposeWin::slotSpellcheckDone(int result)
04199 {
04200 kdDebug(5006) << "spell check complete: result = " << result << endl;
04201 mSpellCheckInProgress=FALSE;
04202
04203 switch( result )
04204 {
04205 case KS_CANCEL:
04206 statusBar()->changeItem(i18n(" Spell check canceled."),0);
04207 break;
04208 case KS_STOP:
04209 statusBar()->changeItem(i18n(" Spell check stopped."),0);
04210 break;
04211 default:
04212 statusBar()->changeItem(i18n(" Spell check complete."),0);
04213 break;
04214 }
04215 QTimer::singleShot( 2000, this, SLOT(slotSpellcheckDoneClearStatus()) );
04216 }
04217
04218 void KMComposeWin::slotSpellcheckDoneClearStatus()
04219 {
04220 statusBar()->changeItem("", 0);
04221 }
04222
04223
04224
04225 void KMComposeWin::slotIdentityChanged( uint uoid )
04226 {
04227 const KPIM::Identity & ident =
04228 kmkernel->identityManager()->identityForUoid( uoid );
04229 if( ident.isNull() ) return;
04230
04231 if( !ident.fullEmailAddr().isNull() )
04232 mEdtFrom->setText(ident.fullEmailAddr());
04233
04234 if ( KPIM::getFirstEmailAddress( from() ).isEmpty() )
04235 mShowHeaders |= HDR_FROM;
04236 if ( mEdtReplyTo ) mEdtReplyTo->setText(ident.replyToAddr());
04237
04238 if ( mRecipientsEditor ) {
04239
04240 const KPIM::Identity & oldIdentity =
04241 kmkernel->identityManager()->identityForUoidOrDefault( mId );
04242 if ( oldIdentity.bcc() != ident.bcc() ) {
04243 mRecipientsEditor->removeRecipient( oldIdentity.bcc(), Recipient::Bcc );
04244 mRecipientsEditor->addRecipient( ident.bcc(), Recipient::Bcc );
04245 }
04246 }
04247
04248
04249
04250 if( mEdtBcc && !mEdtBcc->edited() && !ident.bcc().isEmpty() ) {
04251
04252
04253 if( !mEdtBcc->text().isEmpty() && mEdtBcc->text() != ident.bcc() && !mEdtBcc->edited() ) {
04254 mEdtBcc->setText( ident.bcc() );
04255 } else {
04256
04257
04258
04259 if ( mEdtBcc->text() != ident.bcc() && !mEdtBcc->text().isEmpty() ) {
04260 QString temp_string( mEdtBcc->text() + QString::fromLatin1(",") + ident.bcc() );
04261 mEdtBcc->setText( temp_string );
04262 } else {
04263
04264
04265 mEdtBcc->setText( ident.bcc() );
04266 }
04267 }
04268 }
04269
04270
04271
04272 if( mEdtBcc && mEdtBcc->edited() && !ident.bcc().isEmpty() ) {
04273 if( !mEdtBcc->text().isEmpty() ) {
04274 QString temp_string ( mEdtBcc->text() + QString::fromLatin1(",") + ident.bcc() );
04275 mEdtBcc->setText( temp_string );
04276 } else {
04277 mEdtBcc->setText( ident.bcc() );
04278 }
04279 }
04280
04281
04282
04283 if( mEdtBcc && !mEdtBcc->edited() && ident.bcc().isEmpty() ) {
04284 mEdtBcc->setText( ident.bcc() );
04285 }
04286
04287 if ( !ident.bcc().isEmpty() ) {
04288 mShowHeaders |= HDR_BCC;
04289 }
04290
04291 if ( ident.organization().isEmpty() )
04292 mMsg->removeHeaderField("Organization");
04293 else
04294 mMsg->setHeaderField("Organization", ident.organization());
04295
04296 if (!ident.isXFaceEnabled() || ident.xface().isEmpty())
04297 mMsg->removeHeaderField("X-Face");
04298 else
04299 {
04300 QString xface = ident.xface();
04301 if (!xface.isEmpty())
04302 {
04303 int numNL = ( xface.length() - 1 ) / 70;
04304 for ( int i = numNL; i > 0; --i )
04305 xface.insert( i*70, "\n\t" );
04306 mMsg->setHeaderField("X-Face", xface);
04307 }
04308 }
04309
04310 if ( !mBtnTransport->isChecked() ) {
04311 QString transp = ident.transport();
04312 if ( transp.isEmpty() )
04313 {
04314 mMsg->removeHeaderField("X-KMail-Transport");
04315 transp = GlobalSettings::self()->defaultTransport();
04316 }
04317 else
04318 mMsg->setHeaderField("X-KMail-Transport", transp);
04319 setTransport( transp );
04320 }
04321
04322 mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
04323
04324 if ( !mBtnFcc->isChecked() ) {
04325 setFcc( ident.fcc() );
04326 }
04327
04328 QString edtText = mEditor->text();
04329
04330 if ( mOldSigText.isEmpty() ) {
04331 const KPIM::Identity &id =
04332 kmkernel->
04333 identityManager()->
04334 identityForUoidOrDefault( mMsg->headerField( "X-KMail-Identity" ).
04335 stripWhiteSpace().toUInt() );
04336 mOldSigText = id.signatureText();
04337 }
04338
04339
04340
04341 while ( !edtText.isEmpty() && edtText[edtText.length()-1].isSpace() )
04342 edtText.truncate( edtText.length() - 1 );
04343
04344 while ( !mOldSigText.isEmpty() && mOldSigText[mOldSigText.length()-1].isSpace() )
04345 mOldSigText.truncate( mOldSigText.length() - 1 );
04346
04347 if( edtText.endsWith( mOldSigText ) )
04348 edtText.truncate( edtText.length() - mOldSigText.length() );
04349
04350
04351 mOldSigText = ident.signatureText();
04352 if( ( !mOldSigText.isEmpty() ) &&
04353 ( GlobalSettings::self()->autoTextSignature() == "auto" ) ) {
04354 edtText.append( mOldSigText );
04355 }
04356 mEditor->setText( edtText );
04357
04358
04359
04360 bool bNewIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
04361 bool bNewIdentityHasEncryptionKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
04362 mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
04363 !ident.pgpEncryptionKey().isEmpty() );
04364
04365 if ( !bNewIdentityHasEncryptionKey && mLastIdentityHasEncryptionKey ) {
04366 mLastEncryptActionState = mEncryptAction->isChecked();
04367 setEncryption( false );
04368 }
04369 if ( !bNewIdentityHasSigningKey && mLastIdentityHasSigningKey ) {
04370 mLastSignActionState = mSignAction->isChecked();
04371 setSigning( false );
04372 }
04373
04374 if ( bNewIdentityHasEncryptionKey && !mLastIdentityHasEncryptionKey )
04375 setEncryption( mLastEncryptActionState );
04376 if ( bNewIdentityHasSigningKey && !mLastIdentityHasSigningKey )
04377 setSigning( mLastSignActionState );
04378
04379 mLastIdentityHasSigningKey = bNewIdentityHasSigningKey;
04380 mLastIdentityHasEncryptionKey = bNewIdentityHasEncryptionKey;
04381
04382 setModified( true );
04383 mId = uoid;
04384
04385
04386 rethinkFields( false );
04387 }
04388
04389
04390 void KMComposeWin::slotSpellcheckConfig()
04391 {
04392 KDialogBase dlg(KDialogBase::Plain, i18n("Spellchecker"),
04393 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok,
04394 this, 0, true, true );
04395 KWin kwin;
04396 QTabDialog qtd (this, "tabdialog", true);
04397 KSpellConfig mKSpellConfig (&qtd);
04398 mKSpellConfig.layout()->setMargin( KDialog::marginHint() );
04399
04400 qtd.addTab (&mKSpellConfig, i18n("Spellchecker"));
04401 qtd.setCancelButton ();
04402
04403 kwin.setIcons (qtd.winId(), kapp->icon(), kapp->miniIcon());
04404 qtd.setCancelButton(KStdGuiItem::cancel().text());
04405 qtd.setOkButton(KStdGuiItem::ok().text());
04406
04407 if (qtd.exec())
04408 mKSpellConfig.writeGlobalSettings();
04409 }
04410
04411
04412 void KMComposeWin::slotStatusMessage(const QString &message)
04413 {
04414 statusBar()->changeItem( message, 0 );
04415 }
04416
04417 void KMComposeWin::slotEditToolbars()
04418 {
04419 saveMainWindowSettings(KMKernel::config(), "Composer");
04420 KEditToolbar dlg(guiFactory(), this);
04421
04422 connect( &dlg, SIGNAL(newToolbarConfig()),
04423 SLOT(slotUpdateToolbars()) );
04424
04425 dlg.exec();
04426 }
04427
04428 void KMComposeWin::slotUpdateToolbars()
04429 {
04430 createGUI("kmcomposerui.rc");
04431 applyMainWindowSettings(KMKernel::config(), "Composer");
04432 }
04433
04434 void KMComposeWin::slotEditKeys()
04435 {
04436 KKeyDialog::configure( actionCollection(),
04437 false
04438 );
04439 }
04440
04441 void KMComposeWin::setReplyFocus( bool hasMessage )
04442 {
04443 mEditor->setFocus();
04444 if ( hasMessage )
04445 mEditor->setCursorPosition( 1, 0 );
04446 }
04447
04448 void KMComposeWin::setFocusToSubject()
04449 {
04450 mEdtSubject->setFocus();
04451 }
04452
04453 int KMComposeWin::autoSaveInterval() const
04454 {
04455 return GlobalSettings::self()->autosaveInterval() * 1000 * 60;
04456 }
04457
04458 void KMComposeWin::initAutoSave()
04459 {
04460 kdDebug(5006) << k_funcinfo << endl;
04461
04462 KMFolderMaildir::createMaildirFolders( KMKernel::localDataPath() + "autosave" );
04463 if ( mAutoSaveFilename.isEmpty() ) {
04464 mAutoSaveFilename = KMFolderMaildir::constructValidFileName();
04465 }
04466
04467 updateAutoSave();
04468 }
04469
04470 void KMComposeWin::updateAutoSave()
04471 {
04472 if ( autoSaveInterval() == 0 ) {
04473 delete mAutoSaveTimer; mAutoSaveTimer = 0;
04474 }
04475 else {
04476 if ( !mAutoSaveTimer ) {
04477 mAutoSaveTimer = new QTimer( this );
04478 connect( mAutoSaveTimer, SIGNAL( timeout() ),
04479 this, SLOT( autoSaveMessage() ) );
04480 }
04481 mAutoSaveTimer->start( autoSaveInterval() );
04482 }
04483 }
04484
04485 void KMComposeWin::setAutoSaveFilename( const QString & filename )
04486 {
04487 if ( !mAutoSaveFilename.isEmpty() )
04488 KMFolderMaildir::removeFile( KMKernel::localDataPath() + "autosave",
04489 mAutoSaveFilename );
04490 mAutoSaveFilename = filename;
04491 }
04492
04493 void KMComposeWin::cleanupAutoSave()
04494 {
04495 delete mAutoSaveTimer; mAutoSaveTimer = 0;
04496 if ( !mAutoSaveFilename.isEmpty() ) {
04497 kdDebug(5006) << k_funcinfo << "deleting autosave file "
04498 << mAutoSaveFilename << endl;
04499 KMFolderMaildir::removeFile( KMKernel::localDataPath() + "autosave",
04500 mAutoSaveFilename );
04501 mAutoSaveFilename = QString();
04502 }
04503 }
04504
04505 void KMComposeWin::slotCompletionModeChanged( KGlobalSettings::Completion mode)
04506 {
04507 GlobalSettings::self()->setCompletionMode( (int) mode );
04508
04509
04510 mEdtFrom->setCompletionMode( mode );
04511 mEdtReplyTo->setCompletionMode( mode );
04512 if ( mClassicalRecipients ) {
04513 mEdtTo->setCompletionMode( mode );
04514 mEdtCc->setCompletionMode( mode );
04515 mEdtBcc->setCompletionMode( mode );
04516 }
04517 }
04518
04519 void KMComposeWin::slotConfigChanged()
04520 {
04521 readConfig();
04522 updateAutoSave();
04523 rethinkFields();
04524 }
04525
04526
04527
04528
04529
04530 void KMComposeWin::slotFolderRemoved(KMFolder* folder)
04531 {
04532 if ( (mFolder) && (folder->idString() == mFolder->idString()) )
04533 {
04534 mFolder = kmkernel->draftsFolder();
04535 kdDebug(5006) << "restoring drafts to " << mFolder->idString() << endl;
04536 }
04537 if (mMsg) mMsg->setParent(0);
04538 }
04539
04540
04541 void KMComposeWin::editorFocusChanged(bool gained)
04542 {
04543 mPasteQuotation->setEnabled(gained);
04544 mAddQuoteChars->setEnabled(gained);
04545 mRemQuoteChars->setEnabled(gained);
04546 }
04547
04548 void KMComposeWin::slotSetAlwaysSend( bool bAlways )
04549 {
04550 mAlwaysSend = bAlways;
04551 }
04552
04553 void KMComposeWin::slotListAction( const QString& style )
04554 {
04555 toggleMarkup(true);
04556 if ( style == i18n( "Standard" ) )
04557 mEditor->setParagType( QStyleSheetItem::DisplayBlock, QStyleSheetItem::ListDisc );
04558 else if ( style == i18n( "Bulleted List (Disc)" ) )
04559 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDisc );
04560 else if ( style == i18n( "Bulleted List (Circle)" ) )
04561 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListCircle );
04562 else if ( style == i18n( "Bulleted List (Square)" ) )
04563 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListSquare );
04564 else if ( style == i18n( "Ordered List (Decimal)" ))
04565 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDecimal );
04566 else if ( style == i18n( "Ordered List (Alpha lower)" ) )
04567 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListLowerAlpha );
04568 else if ( style == i18n( "Ordered List (Alpha upper)" ) )
04569 mEditor->setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListUpperAlpha );
04570 mEditor->viewport()->setFocus();
04571 }
04572
04573 void KMComposeWin::slotFontAction( const QString& font)
04574 {
04575 toggleMarkup(true);
04576 mEditor->QTextEdit::setFamily( font );
04577 mEditor->viewport()->setFocus();
04578 }
04579
04580 void KMComposeWin::slotSizeAction( int size )
04581 {
04582 toggleMarkup(true);
04583 mEditor->setPointSize( size );
04584 mEditor->viewport()->setFocus();
04585 }
04586
04587 void KMComposeWin::slotAlignLeft()
04588 {
04589 toggleMarkup(true);
04590 mEditor->QTextEdit::setAlignment( AlignLeft );
04591 }
04592
04593 void KMComposeWin::slotAlignCenter()
04594 {
04595 toggleMarkup(true);
04596 mEditor->QTextEdit::setAlignment( AlignHCenter );
04597 }
04598
04599 void KMComposeWin::slotAlignRight()
04600 {
04601 toggleMarkup(true);
04602 mEditor->QTextEdit::setAlignment( AlignRight );
04603 }
04604
04605 void KMComposeWin::slotTextBold()
04606 {
04607 toggleMarkup(true);
04608 mEditor->QTextEdit::setBold( textBoldAction->isChecked() );
04609 }
04610
04611 void KMComposeWin::slotTextItalic()
04612 {
04613 toggleMarkup(true);
04614 mEditor->QTextEdit::setItalic( textItalicAction->isChecked() );
04615 }
04616
04617 void KMComposeWin::slotTextUnder()
04618 {
04619 toggleMarkup(true);
04620 mEditor->QTextEdit::setUnderline( textUnderAction->isChecked() );
04621 }
04622
04623 void KMComposeWin::slotFormatReset()
04624 {
04625 mEditor->setColor(mForeColor);
04626 mEditor->setCurrentFont( mSaveFont );
04627 }
04628 void KMComposeWin::slotTextColor()
04629 {
04630 QColor color = mEditor->color();
04631
04632 if ( KColorDialog::getColor( color, this ) ) {
04633 toggleMarkup(true);
04634 mEditor->setColor( color );
04635 }
04636 }
04637
04638 void KMComposeWin::fontChanged( const QFont &f )
04639 {
04640 QFont fontTemp = f;
04641 fontTemp.setBold( true );
04642 fontTemp.setItalic( true );
04643 QFontInfo fontInfo( fontTemp );
04644
04645 if ( fontInfo.bold() ) {
04646 textBoldAction->setChecked( f.bold() );
04647 textBoldAction->setEnabled( true ) ;
04648 } else {
04649 textBoldAction->setEnabled( false );
04650 }
04651
04652 if ( fontInfo.italic() ) {
04653 textItalicAction->setChecked( f.italic() );
04654 textItalicAction->setEnabled( true ) ;
04655 } else {
04656 textItalicAction->setEnabled( false );
04657 }
04658
04659 textUnderAction->setChecked( f.underline() );
04660
04661 fontAction->setFont( f.family() );
04662 fontSizeAction->setFontSize( f.pointSize() );
04663 }
04664
04665 void KMComposeWin::alignmentChanged( int a )
04666 {
04667
04668 alignLeftAction->setChecked( ( a == AlignAuto ) || ( a & AlignLeft ) );
04669 alignCenterAction->setChecked( ( a & AlignHCenter ) );
04670 alignRightAction->setChecked( ( a & AlignRight ) );
04671 }
04672
04673 namespace {
04674 class KToggleActionResetter {
04675 KToggleAction * mAction;
04676 bool mOn;
04677 public:
04678 KToggleActionResetter( KToggleAction * action, bool on )
04679 : mAction( action ), mOn( on ) {}
04680 ~KToggleActionResetter() {
04681 if ( mAction )
04682 mAction->setChecked( mOn );
04683 }
04684 void disable() { mAction = 0; }
04685 };
04686 }
04687
04688 void KMComposeWin::slotEncryptChiasmusToggled( bool on ) {
04689 mEncryptWithChiasmus = false;
04690
04691 if ( !on )
04692 return;
04693
04694 KToggleActionResetter resetter( mEncryptChiasmusAction, false );
04695
04696 const Kleo::CryptoBackend::Protocol * chiasmus =
04697 Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
04698
04699 if ( !chiasmus ) {
04700 const QString msg = Kleo::CryptoBackendFactory::instance()->knowsAboutProtocol( "Chiasmus" )
04701 ? i18n( "Please configure a Crypto Backend to use for "
04702 "Chiasmus encryption first.\n"
04703 "You can do this in the Crypto Backends tab of "
04704 "the configure dialog's Security page." )
04705 : i18n( "It looks as though libkleopatra was compiled without "
04706 "Chiasmus support. You might want to recompile "
04707 "libkleopatra with --enable-chiasmus.");
04708 KMessageBox::information( this, msg, i18n("No Chiasmus Backend Configured" ) );
04709 return;
04710 }
04711
04712 STD_NAMESPACE_PREFIX auto_ptr<Kleo::SpecialJob> job( chiasmus->specialJob( "x-obtain-keys", QMap<QString,QVariant>() ) );
04713 if ( !job.get() ) {
04714 const QString msg = i18n( "Chiasmus backend does not offer the "
04715 "\"x-obtain-keys\" function. Please report this bug." );
04716 KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
04717 return;
04718 }
04719
04720 if ( job->exec() ) {
04721 job->showErrorDialog( this, i18n( "Chiasmus Backend Error" ) );
04722 return;
04723 }
04724
04725 const QVariant result = job->property( "result" );
04726 if ( result.type() != QVariant::StringList ) {
04727 const QString msg = i18n( "Unexpected return value from Chiasmus backend: "
04728 "The \"x-obtain-keys\" function did not return a "
04729 "string list. Please report this bug." );
04730 KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
04731 return;
04732 }
04733
04734 const QStringList keys = result.toStringList();
04735 if ( keys.empty() ) {
04736 const QString msg = i18n( "No keys have been found. Please check that a "
04737 "valid key path has been set in the Chiasmus "
04738 "configuration." );
04739 KMessageBox::information( this, msg, i18n( "No Chiasmus Keys Found" ) );
04740 return;
04741 }
04742
04743 ChiasmusKeySelector selectorDlg( this, i18n( "Chiasmus Encryption Key Selection" ),
04744 keys, GlobalSettings::chiasmusKey(),
04745 GlobalSettings::chiasmusOptions() );
04746 if ( selectorDlg.exec() != QDialog::Accepted )
04747 return;
04748
04749 GlobalSettings::setChiasmusOptions( selectorDlg.options() );
04750 GlobalSettings::setChiasmusKey( selectorDlg.key() );
04751 assert( !GlobalSettings::chiasmusKey().isEmpty() );
04752 mEncryptWithChiasmus = true;
04753 resetter.disable();
04754 }
04755
04756
04757