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