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