kmail

kmcomposewin.cpp
1// kmcomposewin.cpp
2// Author: Markus Wuebben <markus.wuebben@kde.org>
3// This code is published under the GPL.
4
5#undef GrayScale
6#undef Color
7#include <config.h>
8
9#define REALLY_WANT_KMCOMPOSEWIN_H
10#include "kmcomposewin.h"
11#undef REALLY_WANT_KMCOMPOSEWIN_H
12
13#include "kmedit.h"
14#include "kmlineeditspell.h"
15#include "kmatmlistview.h"
16
17#include "kmmainwin.h"
18#include "kmreadermainwin.h"
19#include "messagesender.h"
20#include "kmmsgpartdlg.h"
21#include <kpgpblock.h>
22#include <kaddrbook.h>
23#include "kmaddrbook.h"
24#include "kmmsgdict.h"
25#include "kmfolderimap.h"
26#include "kmfoldermgr.h"
27#include "kmfoldercombobox.h"
28#include "kmtransport.h"
29#include "kmcommands.h"
30#include "kcursorsaver.h"
31#include "partNode.h"
32#include "encodingdetector.h"
33#include "attachmentlistview.h"
34#include "transportmanager.h"
35using KMail::AttachmentListView;
36#include "dictionarycombobox.h"
38#include "addressesdialog.h"
39using KPIM::AddressesDialog;
40#include "addresseeemailselection.h"
41using KPIM::AddresseeEmailSelection;
42using KPIM::AddresseeSelectorDialog;
43#include <maillistdrag.h>
44using KPIM::MailListDrag;
45#include "recentaddresses.h"
46using TDERecentAddress::RecentAddresses;
47#include "kleo_util.h"
48#include "stl_util.h"
49#include "recipientseditor.h"
50#include "editorwatcher.h"
51
52#include "attachmentcollector.h"
53#include "objecttreeparser.h"
54
55#include "kmfoldermaildir.h"
56
57#include <libkpimidentities/identitymanager.h>
58#include <libkpimidentities/identitycombo.h>
59#include <libkpimidentities/identity.h>
60#include <libtdepim/tdefileio.h>
61#include <libemailfunctions/email.h>
62#include <kleo/cryptobackendfactory.h>
63#include <kleo/exportjob.h>
64#include <kleo/specialjob.h>
65#include <ui/progressdialog.h>
66#include <ui/keyselectiondialog.h>
67
68#include <gpgmepp/context.h>
69#include <gpgmepp/key.h>
70
71#include <tdeio/netaccess.h>
72
73#include "tdelistboxdialog.h"
74
75#include "messagecomposer.h"
76#include "chiasmuskeyselector.h"
77
78#include <kcharsets.h>
79#include <tdecompletionbox.h>
80#include <kcursor.h>
81#include <kcombobox.h>
82#include <tdestdaccel.h>
83#include <tdepopupmenu.h>
84#include <kedittoolbar.h>
85#include <kkeydialog.h>
86#include <kdebug.h>
87#include <tdefiledialog.h>
88#include <twin.h>
89#include <kinputdialog.h>
90#include <tdemessagebox.h>
91#include <kurldrag.h>
92#include <tdeio/scheduler.h>
93#include <tdetempfile.h>
94#include <tdelocale.h>
95#include <tdeapplication.h>
96#include <kstatusbar.h>
97#include <tdeaction.h>
98#include <kstdaction.h>
99#include <kdirwatch.h>
100#include <kstdguiitem.h>
101#include <kiconloader.h>
102#include <kpushbutton.h>
103#include <kuserprofile.h>
104#include <krun.h>
105#include <ktempdir.h>
106#include <tdestandarddirs.h>
107//#include <keditlistbox.h>
108#include "globalsettings.h"
109#include "replyphrases.h"
110
111#include <tdespell.h>
112#include <tdespelldlg.h>
113#include <spellingfilter.h>
114#include <ksyntaxhighlighter.h>
115#include <kcolordialog.h>
116#include <kzip.h>
117#include <ksavefile.h>
118
119#include <tqtabdialog.h>
120#include <tqregexp.h>
121#include <tqbuffer.h>
122#include <tqtooltip.h>
123#include <tqtextcodec.h>
124#include <tqheader.h>
125#include <tqwhatsthis.h>
126#include <tqfontdatabase.h>
127
128#include <mimelib/mimepp.h>
129
130#include <algorithm>
131#include <memory>
132
133#include <sys/stat.h>
134#include <sys/types.h>
135#include <stdlib.h>
136#include <unistd.h>
137#include <errno.h>
138#include <fcntl.h>
139#include <assert.h>
140
141#include "kmcomposewin.moc"
142
143#include "snippetwidget.h"
144
145KMail::Composer * KMail::makeComposer( KMMessage * msg, uint identitiy ) {
146 return KMComposeWin::create( msg, identitiy );
147}
148
149KMail::Composer * KMComposeWin::create( KMMessage * msg, uint identitiy ) {
150 return new KMComposeWin( msg, identitiy );
151}
152
153//-----------------------------------------------------------------------------
154KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
155 : MailComposerIface(), KMail::Composer( "kmail-composer#" ),
156 mSpellCheckInProgress( false ),
157 mDone( false ),
158 mAtmModified( false ),
159 mAtmSelectNew( 0 ),
160 mMsg( 0 ),
161 mAttachMenu( 0 ),
162 mSigningAndEncryptionExplicitlyDisabled( false ),
163 mFolder( 0 ),
164 mUseHTMLEditor( false ),
165 mId( id ),
166 mAttachPK( 0 ), mAttachMPK( 0 ),
167 mAttachRemoveAction( 0 ), mAttachSaveAction( 0 ), mAttachPropertiesAction( 0 ),
168 mAppendSignatureAction( 0 ), mPrependSignatureAction( 0 ), mInsertSignatureAction( 0 ),
169 mSignAction( 0 ), mEncryptAction( 0 ), mRequestMDNAction( 0 ),
170 mUrgentAction( 0 ), mAllFieldsAction( 0 ), mFromAction( 0 ),
171 mReplyToAction( 0 ), mToAction( 0 ), mCcAction( 0 ), mBccAction( 0 ),
172 mSubjectAction( 0 ),
173 mIdentityAction( 0 ), mTransportAction( 0 ), mFccAction( 0 ),
174 mWordWrapAction( 0 ), mFixedFontAction( 0 ), mAutoSpellCheckingAction( 0 ),
175 mDictionaryAction( 0 ), mSnippetAction( 0 ),
176 mEncodingAction( 0 ),
177 mCryptoModuleAction( 0 ),
178 mEncryptChiasmusAction( 0 ),
179 mEncryptWithChiasmus( false ),
180 mComposer( 0 ),
181 mLabelWidth( 0 ),
182 mAutoSaveTimer( 0 ), mLastAutoSaveErrno( 0 ),
183 mSignatureStateIndicator( 0 ), mEncryptionStateIndicator( 0 ),
184 mPreserveUserCursorPosition( false ),
185 mPreventFccOverwrite( false ),
186 mCheckForRecipients( true ),
187 mCheckForForgottenAttachments( true ),
188 mIgnoreStickyFields( false )
189{
190 mClassicalRecipients = GlobalSettings::self()->recipientsEditorType() ==
191 GlobalSettings::EnumRecipientsEditorType::Classic;
192
193 mSubjectTextWasSpellChecked = false;
194 if (kmkernel->xmlGuiInstance())
195 setInstance( kmkernel->xmlGuiInstance() );
196 mMainWidget = new TQWidget(this);
197 // splitter between the headers area and the actual editor
198 mHeadersToEditorSplitter = new TQSplitter( TQt::Vertical, mMainWidget, "mHeadersToEditorSplitter" );
199 mHeadersToEditorSplitter->setChildrenCollapsible( false );
200 mHeadersArea = new TQWidget( mHeadersToEditorSplitter );
201 mHeadersArea->setSizePolicy( mHeadersToEditorSplitter->sizePolicy().horData(), TQSizePolicy::Maximum );
202 TQVBoxLayout *v = new TQVBoxLayout( mMainWidget );
203 v->addWidget( mHeadersToEditorSplitter );
204 mIdentity = new KPIM::IdentityCombo(kmkernel->identityManager(), mHeadersArea);
205 TQToolTip::add( mIdentity,
206 i18n( "Select an identity for this message" ) );
207
208 mDictionaryCombo = new DictionaryComboBox( mHeadersArea );
209 TQToolTip::add( mDictionaryCombo,
210 i18n( "Select the dictionary to use when spell-checking this message" ) );
211
212 mFcc = new KMFolderComboBox(mHeadersArea);
213 mFcc->showOutboxFolder( false );
214 TQToolTip::add( mFcc,
215 i18n( "Select the sent-mail folder where a copy of this message will be saved" ) );
216
217 mTransport = new TQComboBox(true, mHeadersArea);
218 TQToolTip::add( mTransport,
219 i18n( "Select the outgoing account to use for sending this message" ) );
220
221 mEdtFrom = new KMLineEdit(false,mHeadersArea, "fromLine");
222 TQToolTip::add( mEdtFrom,
223 i18n( "Set the \"From:\" email address for this message" ) );
224
225 mEdtReplyTo = new KMLineEdit(true,mHeadersArea, "replyToLine");
226 TQToolTip::add( mEdtReplyTo,
227 i18n( "Set the \"Reply-To:\" email address for this message" ) );
228 connect(mEdtReplyTo,TQ_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
229 TQ_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
230
231 if ( mClassicalRecipients ) {
232 mRecipientsEditor = 0;
233
234 mEdtTo = new KMLineEdit(true,mHeadersArea, "toLine");
235 mEdtCc = new KMLineEdit(true,mHeadersArea, "ccLine");
236 mEdtBcc = new KMLineEdit(true,mHeadersArea, "bccLine");
237
238 mLblTo = new TQLabel(mHeadersArea);
239 mLblCc = new TQLabel(mHeadersArea);
240 mLblBcc = new TQLabel(mHeadersArea);
241
242 mBtnTo = new TQPushButton("...",mHeadersArea);
243 mBtnCc = new TQPushButton("...",mHeadersArea);
244 mBtnBcc = new TQPushButton("...",mHeadersArea);
245 //mBtnFrom = new TQPushButton("...",mHeadersArea);
246
247 TQString tip = i18n("Select email address(es)");
248 TQToolTip::add( mBtnTo, tip );
249 TQToolTip::add( mBtnCc, tip );
250 TQToolTip::add( mBtnBcc, tip );
251
252 mBtnTo->setFocusPolicy(TQWidget::NoFocus);
253 mBtnCc->setFocusPolicy(TQWidget::NoFocus);
254 mBtnBcc->setFocusPolicy(TQWidget::NoFocus);
255 //mBtnFrom->setFocusPolicy(TQWidget::NoFocus);
256
257 connect(mBtnTo,TQ_SIGNAL(clicked()),TQ_SLOT(slotAddrBookTo()));
258 connect(mBtnCc,TQ_SIGNAL(clicked()),TQ_SLOT(slotAddrBookTo()));
259 connect(mBtnBcc,TQ_SIGNAL(clicked()),TQ_SLOT(slotAddrBookTo()));
260 //connect(mBtnFrom,TQ_SIGNAL(clicked()),TQ_SLOT(slotAddrBookFrom()));
261
262 connect(mEdtTo,TQ_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
263 TQ_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
264 connect(mEdtCc,TQ_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
265 TQ_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
266 connect(mEdtBcc,TQ_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
267 TQ_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
268
269 mEdtTo->setFocus();
270 } else {
271 mEdtTo = 0;
272 mEdtCc = 0;
273 mEdtBcc = 0;
274
275 mLblTo = 0;
276 mLblCc = 0;
277 mLblBcc = 0;
278
279 mBtnTo = 0;
280 mBtnCc = 0;
281 mBtnBcc = 0;
282 //mBtnFrom = 0;
283
284 mRecipientsEditor = new RecipientsEditor( mHeadersArea );
285 connect( mRecipientsEditor,
286 TQ_SIGNAL( completionModeChanged( TDEGlobalSettings::Completion ) ),
287 TQ_SLOT( slotCompletionModeChanged( TDEGlobalSettings::Completion ) ) );
288 connect( mRecipientsEditor, TQ_SIGNAL(sizeHintChanged()), TQ_SLOT(recipientEditorSizeHintChanged()) );
289
290 mRecipientsEditor->setFocus();
291 }
292 mEdtSubject = new KMLineEditSpell(false,mHeadersArea, "subjectLine");
293 TQToolTip::add( mEdtSubject,
294 i18n( "Set a subject for this message" ) );
295
296 mLblIdentity = new TQLabel( i18n("&Identity:"), mHeadersArea );
297 mDictionaryLabel = new TQLabel( i18n("&Dictionary:"), mHeadersArea );
298 mLblFcc = new TQLabel( i18n("&Sent-Mail folder:"), mHeadersArea );
299 mLblTransport = new TQLabel( i18n("&Mail transport:"), mHeadersArea );
300 mLblFrom = new TQLabel( i18n("sender address field", "&From:"), mHeadersArea );
301 mLblReplyTo = new TQLabel( i18n("&Reply to:"), mHeadersArea );
302 mLblSubject = new TQLabel( i18n("S&ubject:"), mHeadersArea );
303
304 TQString sticky = i18n("Sticky");
305 mBtnIdentity = new TQCheckBox(sticky,mHeadersArea);
306 TQToolTip::add( mBtnIdentity,
307 i18n( "Use the selected value as your identity for future messages" ) );
308 mBtnFcc = new TQCheckBox(sticky,mHeadersArea);
309 TQToolTip::add( mBtnFcc,
310 i18n( "Use the selected value as your sent-mail folder for future messages" ) );
311 mBtnTransport = new TQCheckBox(sticky,mHeadersArea);
312 TQToolTip::add( mBtnTransport,
313 i18n( "Use the selected value as your outgoing account for future messages" ) );
314 mBtnDictionary = new TQCheckBox( sticky, mHeadersArea );
315 TQToolTip::add( mBtnDictionary,
316 i18n( "Use the selected value as your dictionary for future messages" ) );
317
318 //setWFlags( WType_TopLevel | WStyle_Dialog );
319 mHtmlMarkup = GlobalSettings::self()->useHtmlMarkup();
320 mShowHeaders = GlobalSettings::self()->headers();
321 mDone = false;
322 mGrid = 0;
323 mAtmListView = 0;
324 mAtmList.setAutoDelete(true);
325 mAtmTempList.setAutoDelete(true);
326 mAtmModified = false;
327 mAutoDeleteMsg = false;
328 mFolder = 0;
329 mAutoCharset = true;
330 mFixedFontAction = 0;
331 mTempDir = 0;
332 // the attachment view is separated from the editor by a splitter
333 mSplitter = new TQSplitter( TQt::Vertical, mHeadersToEditorSplitter, "mSplitter" );
334 mSplitter->setChildrenCollapsible( false );
335 mSnippetSplitter = new TQSplitter( TQt::Horizontal, mSplitter, "mSnippetSplitter");
336 mSnippetSplitter->setChildrenCollapsible( false );
337
338 TQWidget *editorAndCryptoStateIndicators = new TQWidget( mSnippetSplitter );
339 TQVBoxLayout *vbox = new TQVBoxLayout( editorAndCryptoStateIndicators );
340 TQHBoxLayout *hbox = new TQHBoxLayout( vbox );
341 {
342 mSignatureStateIndicator = new TQLabel( editorAndCryptoStateIndicators );
343 mSignatureStateIndicator->setAlignment( TQt::AlignHCenter );
344 hbox->addWidget( mSignatureStateIndicator );
345
346 TDEConfigGroup reader( KMKernel::config(), "Reader" );
347 TQPalette p( mSignatureStateIndicator->palette() );
348
349 TQColor defaultSignedColor( 0x40, 0xFF, 0x40 ); // light green // pgp ok, trusted key
350 TQColor defaultEncryptedColor( 0x00, 0x80, 0xFF ); // light blue // pgp encrypted
351 p.setColor( TQColorGroup::Background, reader.readColorEntry( "PGPMessageOkKeyOk", &defaultSignedColor ) );
352 mSignatureStateIndicator->setPalette( p );
353
354 mEncryptionStateIndicator = new TQLabel( editorAndCryptoStateIndicators );
355 mEncryptionStateIndicator->setAlignment( TQt::AlignHCenter );
356 hbox->addWidget( mEncryptionStateIndicator );
357 p.setColor( TQColorGroup::Background, reader.readColorEntry( "PGPMessageEncr" , &defaultEncryptedColor ) );
358 mEncryptionStateIndicator->setPalette( p );
359 }
360
361 mEditor = new KMEdit( editorAndCryptoStateIndicators, this, mDictionaryCombo->spellConfig() );
362 vbox->addWidget( mEditor );
363
364 mSnippetWidget = new SnippetWidget( mEditor, actionCollection(), mSnippetSplitter );
365 mSnippetWidget->setShown( GlobalSettings::self()->showSnippetManager() );
366
367 // mSplitter->moveToFirst( editorAndCryptoStateIndicators );
368 mSplitter->setOpaqueResize( true );
369
370 mEditor->initializeAutoSpellChecking();
371 mEditor->setTextFormat(TQt::PlainText);
372 mEditor->setAcceptDrops( true );
373
374 TQWhatsThis::add( mBtnIdentity,
375 GlobalSettings::self()->stickyIdentityItem()->whatsThis() );
376 TQWhatsThis::add( mBtnFcc,
377 GlobalSettings::self()->stickyFccItem()->whatsThis() );
378 TQWhatsThis::add( mBtnTransport,
379 GlobalSettings::self()->stickyTransportItem()->whatsThis() );
380 TQWhatsThis::add( mBtnTransport,
381 GlobalSettings::self()->stickyDictionaryItem()->whatsThis() );
382
383 mSpellCheckInProgress=false;
384
385 setCaption( i18n("Composer") );
386 setMinimumSize(200,200);
387
388 mBtnIdentity->setFocusPolicy(TQWidget::NoFocus);
389 mBtnFcc->setFocusPolicy(TQWidget::NoFocus);
390 mBtnTransport->setFocusPolicy(TQWidget::NoFocus);
391 mBtnDictionary->setFocusPolicy( TQWidget::NoFocus );
392
393 mAtmListView = new AttachmentListView( this, mSplitter,
394 "attachment list view" );
395 mAtmListView->setSelectionMode( TQListView::Extended );
396 mAtmListView->addColumn( i18n("Name"), 200 );
397 mAtmListView->addColumn( i18n("Size"), 80 );
398 mAtmListView->addColumn( i18n("Encoding"), 120 );
399 int atmColType = mAtmListView->addColumn( i18n("Type"), 120 );
400 // Stretch "Type".
401 mAtmListView->header()->setStretchEnabled( true, atmColType );
402 mAtmEncryptColWidth = 80;
403 mAtmSignColWidth = 80;
404 mAtmCompressColWidth = 100;
405 mAtmColCompress = mAtmListView->addColumn( i18n("Compress"),
406 mAtmCompressColWidth );
407 mAtmColEncrypt = mAtmListView->addColumn( i18n("Encrypt"),
408 mAtmEncryptColWidth );
409 mAtmColSign = mAtmListView->addColumn( i18n("Sign"),
410 mAtmSignColWidth );
411 mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
412 mAtmListView->setColumnWidth( mAtmColSign, 0 );
413 mAtmListView->setAllColumnsShowFocus( true );
414
415 connect( mAtmListView,
416 TQ_SIGNAL( doubleClicked( TQListViewItem* ) ),
417 TQ_SLOT( slotAttachEdit() ) );
418 connect( mAtmListView,
419 TQ_SIGNAL( rightButtonPressed( TQListViewItem*, const TQPoint&, int ) ),
420 TQ_SLOT( slotAttachPopupMenu( TQListViewItem*, const TQPoint&, int ) ) );
421 connect( mAtmListView,
422 TQ_SIGNAL( selectionChanged() ),
423 TQ_SLOT( slotUpdateAttachActions() ) );
424 connect( mAtmListView,
425 TQ_SIGNAL( attachmentDeleted() ),
426 TQ_SLOT( slotAttachRemove() ) );
427 connect( mAtmListView,
428 TQ_SIGNAL( dragStarted() ),
429 TQ_SLOT( slotAttachmentDragStarted() ) );
430 mAttachMenu = 0;
431
432 readConfig();
433 setupStatusBar();
434 setupActions();
435 setupEditor();
436 slotUpdateSignatureAndEncrypionStateIndicators();
437
438 applyMainWindowSettings(KMKernel::config(), "Composer");
439
440 connect( mEdtSubject, TQ_SIGNAL( subjectTextSpellChecked() ),
441 TQ_SLOT( slotSubjectTextSpellChecked() ) );
442 connect(mEdtSubject,TQ_SIGNAL(textChanged(const TQString&)),
443 TQ_SLOT(slotUpdWinTitle(const TQString&)));
444 connect(mIdentity,TQ_SIGNAL(identityChanged(uint)),
445 TQ_SLOT(slotIdentityChanged(uint)));
446 connect( kmkernel->identityManager(), TQ_SIGNAL(changed(uint)),
447 TQ_SLOT(slotIdentityChanged(uint)));
448
449 connect(mEdtFrom,TQ_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
450 TQ_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
451 connect(kmkernel->folderMgr(),TQ_SIGNAL(folderRemoved(KMFolder*)),
452 TQ_SLOT(slotFolderRemoved(KMFolder*)));
453 connect(kmkernel->imapFolderMgr(),TQ_SIGNAL(folderRemoved(KMFolder*)),
454 TQ_SLOT(slotFolderRemoved(KMFolder*)));
455 connect(kmkernel->dimapFolderMgr(),TQ_SIGNAL(folderRemoved(KMFolder*)),
456 TQ_SLOT(slotFolderRemoved(KMFolder*)));
457 connect( kmkernel, TQ_SIGNAL( configChanged() ),
458 this, TQ_SLOT( slotConfigChanged() ) );
459
460 connect (mEditor, TQ_SIGNAL (spellcheck_done(int)),
461 this, TQ_SLOT (slotSpellcheckDone (int)));
462 connect (mEditor, TQ_SIGNAL( attachPNGImageData(const TQByteArray &) ),
463 this, TQ_SLOT ( slotAttachPNGImageData(const TQByteArray &) ) );
464 connect (mEditor, TQ_SIGNAL( focusChanged(bool) ),
465 this, TQ_SLOT (editorFocusChanged(bool)) );
466
467 mMainWidget->resize(480,510);
468 setCentralWidget(mMainWidget);
469 rethinkFields();
470
471 if ( !mClassicalRecipients ) {
472 // This is ugly, but if it isn't called the line edits in the recipients
473 // editor aren't wide enough until the first resize event comes.
474 rethinkFields();
475 }
476
477 if ( GlobalSettings::self()->useExternalEditor() ) {
478 mEditor->setUseExternalEditor(true);
479 mEditor->setExternalEditorPath( GlobalSettings::self()->externalEditor() );
480 }
481
482 initAutoSave();
483 slotUpdateSignatureActions();
484 mMsg = 0;
485 if (aMsg)
486 setMsg(aMsg);
487 fontChanged( mEditor->currentFont() ); // set toolbar buttons to correct values
488
489 mDone = true;
490}
491
492//-----------------------------------------------------------------------------
493KMComposeWin::~KMComposeWin()
494{
495 writeConfig();
496 if (mFolder && mMsg)
497 {
498 mAutoDeleteMsg = false;
499 mFolder->addMsg(mMsg);
500 // Ensure that the message is correctly and fully parsed
501 mFolder->unGetMsg( mFolder->count() - 1 );
502 }
503 if (mAutoDeleteMsg) {
504 delete mMsg;
505 mMsg = 0;
506 }
507 TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.begin();
508 while ( it != mMapAtmLoadData.end() )
509 {
510 TDEIO::Job *job = it.key();
511 mMapAtmLoadData.remove( it );
512 job->kill();
513 it = mMapAtmLoadData.begin();
514 }
515 deleteAll( mComposedMessages );
516
517 for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
518 delete *it;
519 }
520}
521
522void KMComposeWin::setAutoDeleteWindow( bool f )
523{
524 if ( f )
525 setWFlags( getWFlags() | WDestructiveClose );
526 else
527 setWFlags( getWFlags() & ~WDestructiveClose );
528}
529
530//-----------------------------------------------------------------------------
531void KMComposeWin::send(int how)
532{
533 switch (how) {
534 case 1:
535 slotSendNow();
536 break;
537 default:
538 case 0:
539 // TODO: find out, what the default send method is and send it this way
540 case 2:
541 slotSendLater();
542 break;
543 }
544}
545
546//-----------------------------------------------------------------------------
547void KMComposeWin::addAttachmentsAndSend(const KURL::List &urls, const TQString &/*comment*/, int how)
548{
549 if (urls.isEmpty())
550 {
551 send(how);
552 return;
553 }
554 mAttachFilesSend = how;
555 mAttachFilesPending = urls;
556 connect(this, TQ_SIGNAL(attachmentAdded(const KURL&, bool)), TQ_SLOT(slotAttachedFile(const KURL&)));
557 for( KURL::List::ConstIterator itr = urls.begin(); itr != urls.end(); ++itr ) {
558 if (!addAttach( *itr ))
559 mAttachFilesPending.remove(mAttachFilesPending.find(*itr)); // only remove one copy of the url
560 }
561
562 if (mAttachFilesPending.isEmpty() && mAttachFilesSend == how)
563 {
564 send(mAttachFilesSend);
565 mAttachFilesSend = -1;
566 }
567}
568
569void KMComposeWin::slotAttachedFile(const KURL &url)
570{
571 if (mAttachFilesPending.isEmpty())
572 return;
573 mAttachFilesPending.remove(mAttachFilesPending.find(url)); // only remove one copy of url
574 if (mAttachFilesPending.isEmpty())
575 {
576 send(mAttachFilesSend);
577 mAttachFilesSend = -1;
578 }
579}
580
581//-----------------------------------------------------------------------------
582void KMComposeWin::addAttachment(KURL url,TQString /*comment*/)
583{
584 addAttach(url);
585}
586
587//-----------------------------------------------------------------------------
588void KMComposeWin::addAttachment(const TQString &name,
589 const TQCString &/*cte*/,
590 const TQByteArray &data,
591 const TQCString &type,
592 const TQCString &subType,
593 const TQCString &paramAttr,
594 const TQString &paramValue,
595 const TQCString &contDisp)
596{
597 if (!data.isEmpty()) {
598 KMMessagePart *msgPart = new KMMessagePart;
599 msgPart->setName(name);
600 if( type == "message" && subType == "rfc822" ) {
601 msgPart->setMessageBody( data );
602 } else {
603 TQValueList<int> dummy;
604 msgPart->setBodyAndGuessCte(data, dummy,
605 kmkernel->msgSender()->sendQuotedPrintable());
606 }
607 msgPart->setTypeStr(type);
608 msgPart->setSubtypeStr(subType);
609 msgPart->setParameter(paramAttr,paramValue);
610 msgPart->setContentDisposition(contDisp);
611 addAttach(msgPart);
612 }
613}
614
615//-----------------------------------------------------------------------------
616void KMComposeWin::slotAttachPNGImageData(const TQByteArray &image)
617{
618 bool ok;
619
620 TQString attName = KInputDialog::getText( "KMail", i18n("Name of the attachment:"), TQString(), &ok, this );
621 if ( !ok )
622 return;
623
624 if ( !attName.lower().endsWith(".png") ) attName += ".png";
625
626 addAttachment( attName, "base64", image, "image", "png", TQCString(), TQString(), TQCString() );
627}
628
629//-----------------------------------------------------------------------------
630void KMComposeWin::setBody(TQString body)
631{
632 mEditor->setText(body);
633}
634
635//-----------------------------------------------------------------------------
636bool KMComposeWin::event(TQEvent *e)
637{
638 if (e->type() == TQEvent::ApplicationPaletteChange)
639 {
640 readColorConfig();
641 }
642 return KMail::Composer::event(e);
643}
644
645
646//-----------------------------------------------------------------------------
647void KMComposeWin::readColorConfig(void)
648{
649 if ( GlobalSettings::self()->useDefaultColors() ) {
650 mForeColor = TQColor(tdeApp->palette().active().text());
651 mBackColor = TQColor(tdeApp->palette().active().base());
652 } else {
653 mForeColor = GlobalSettings::self()->foregroundColor();
654 mBackColor = GlobalSettings::self()->backgroundColor();
655 }
656
657 // Color setup
658 mPalette = tdeApp->palette();
659 TQColorGroup cgrp = mPalette.active();
660 cgrp.setColor( TQColorGroup::Base, mBackColor);
661 cgrp.setColor( TQColorGroup::Text, mForeColor);
662 mPalette.setDisabled(cgrp);
663 mPalette.setActive(cgrp);
664 mPalette.setInactive(cgrp);
665
666 mEdtFrom->setPalette(mPalette);
667 mEdtReplyTo->setPalette(mPalette);
668 if ( mClassicalRecipients ) {
669 mEdtTo->setPalette(mPalette);
670 mEdtCc->setPalette(mPalette);
671 mEdtBcc->setPalette(mPalette);
672 }
673 mEdtSubject->setPalette(mPalette);
674 mTransport->setPalette(mPalette);
675 mEditor->setPalette(mPalette);
676 mFcc->setPalette(mPalette);
677}
678
679//-----------------------------------------------------------------------------
680void KMComposeWin::readConfig( bool reload /* = false */ )
681{
682 mDefCharset = KMMessage::defaultCharset();
683 mBtnIdentity->setChecked( GlobalSettings::self()->stickyIdentity() );
684 if (mBtnIdentity->isChecked()) {
685 mId = (GlobalSettings::self()->previousIdentity()!=0) ?
686 GlobalSettings::self()->previousIdentity() : mId;
687 }
688 mBtnFcc->setChecked( GlobalSettings::self()->stickyFcc() );
689 mBtnTransport->setChecked( GlobalSettings::self()->stickyTransport() );
690 mBtnDictionary->setChecked( GlobalSettings::self()->stickyDictionary() );
691 TQStringList transportHistory = GlobalSettings::self()->transportHistory();
692 TQString currentTransport = GlobalSettings::self()->currentTransport();
693
694 mEdtFrom->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
695 mEdtReplyTo->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
696 if ( mClassicalRecipients ) {
697 mEdtTo->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
698 mEdtCc->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
699 mEdtBcc->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
700 }
701 else
702 mRecipientsEditor->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
703
704 readColorConfig();
705
706 if ( GlobalSettings::self()->useDefaultFonts() ) {
707 mBodyFont = TDEGlobalSettings::generalFont();
708 mFixedFont = TDEGlobalSettings::fixedFont();
709 } else {
710 mBodyFont = GlobalSettings::self()->composerFont();
711 mFixedFont = GlobalSettings::self()->fixedFont();
712 }
713
714 slotUpdateFont();
715 mEdtFrom->setFont(mBodyFont);
716 mEdtReplyTo->setFont(mBodyFont);
717 if ( mClassicalRecipients ) {
718 mEdtTo->setFont(mBodyFont);
719 mEdtCc->setFont(mBodyFont);
720 mEdtBcc->setFont(mBodyFont);
721 }
722 mEdtSubject->setFont(mBodyFont);
723
724 if ( !reload ) {
725 TQSize siz = GlobalSettings::self()->composerSize();
726 if (siz.width() < 200) siz.setWidth(200);
727 if (siz.height() < 200) siz.setHeight(200);
728 resize(siz);
729
730 if ( !GlobalSettings::self()->snippetSplitterPosition().isEmpty() ) {
731 mSnippetSplitter->setSizes( GlobalSettings::self()->snippetSplitterPosition() );
732 } else {
733 TQValueList<int> defaults;
734 defaults << (int)(width() * 0.8) << (int)(width() * 0.2);
735 mSnippetSplitter->setSizes( defaults );
736 }
737 }
738
739 mIdentity->setCurrentIdentity( mId );
740
741 kdDebug(5006) << "KMComposeWin::readConfig. " << mIdentity->currentIdentityName() << endl;
742 const KPIM::Identity & ident =
743 kmkernel->identityManager()->identityForUoid( mIdentity->currentIdentity() );
744
745 mTransport->clear();
746 mTransport->insertStringList( KMTransportInfo::availableTransports() );
747 while ( transportHistory.count() > (uint)GlobalSettings::self()->maxTransportEntries() )
748 transportHistory.remove( transportHistory.last() );
749 mTransport->insertStringList( transportHistory );
750 mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
751 if ( mBtnTransport->isChecked() ) {
752 setTransport( currentTransport );
753 }
754
755 if ( mBtnDictionary->isChecked() ) {
756 mDictionaryCombo->setCurrentByDictionaryName( GlobalSettings::self()->previousDictionary() );
757 } else {
758 mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
759 }
760
761 TQString fccName = "";
762 if ( mBtnFcc->isChecked() ) {
763 fccName = GlobalSettings::self()->previousFcc();
764 } else if ( !ident.fcc().isEmpty() ) {
765 fccName = ident.fcc();
766 }
767
768 setFcc( fccName );
769}
770
771//-----------------------------------------------------------------------------
772void KMComposeWin::writeConfig(void)
773{
774 GlobalSettings::self()->setHeaders( mShowHeaders );
775 GlobalSettings::self()->setStickyFcc( mBtnFcc->isChecked() );
776 if ( !mIgnoreStickyFields ) {
777 GlobalSettings::self()->setCurrentTransport( mTransport->currentText() );
778 GlobalSettings::self()->setStickyTransport( mBtnTransport->isChecked() );
779 GlobalSettings::self()->setStickyDictionary( mBtnDictionary->isChecked() );
780 GlobalSettings::self()->setStickyIdentity( mBtnIdentity->isChecked() );
781 GlobalSettings::self()->setPreviousIdentity( mIdentity->currentIdentity() );
782 }
783 GlobalSettings::self()->setPreviousFcc( mFcc->getFolder()->idString() );
784 GlobalSettings::self()->setPreviousDictionary( mDictionaryCombo->currentDictionaryName() );
785 GlobalSettings::self()->setAutoSpellChecking(
786 mAutoSpellCheckingAction->isChecked() );
787 TQStringList transportHistory = GlobalSettings::self()->transportHistory();
788 transportHistory.remove(mTransport->currentText());
789 if (KMTransportInfo::availableTransports().findIndex(mTransport
790 ->currentText()) == -1) {
791 transportHistory.prepend(mTransport->currentText());
792 }
793 GlobalSettings::self()->setTransportHistory( transportHistory );
794 GlobalSettings::self()->setUseFixedFont( mFixedFontAction->isChecked() );
795 GlobalSettings::self()->setUseHtmlMarkup( mHtmlMarkup );
796 GlobalSettings::self()->setComposerSize( size() );
797 GlobalSettings::self()->setShowSnippetManager( mSnippetAction->isChecked() );
798
799 TDEConfigGroupSaver saver( KMKernel::config(), "Geometry" );
800 saveMainWindowSettings( KMKernel::config(), "Composer" );
801 GlobalSettings::setSnippetSplitterPosition( mSnippetSplitter->sizes() );
802
803 // make sure config changes are written to disk, cf. bug 127538
804 GlobalSettings::self()->writeConfig();
805}
806
807//-----------------------------------------------------------------------------
808void KMComposeWin::autoSaveMessage()
809{
810 kdDebug(5006) << k_funcinfo << endl;
811 if ( !mMsg || mComposer || mAutoSaveFilename.isEmpty() )
812 return;
813 kdDebug(5006) << k_funcinfo << "autosaving message" << endl;
814
815 if ( mAutoSaveTimer )
816 mAutoSaveTimer->stop();
817
818 connect( this, TQ_SIGNAL( applyChangesDone( bool ) ),
819 this, TQ_SLOT( slotContinueAutoSave() ) );
820 // This method is called when KMail crashed, so don't try signing/encryption
821 // and don't disable controls because it is also called from a timer and
822 // then the disabling is distracting.
823 applyChanges( true, true );
824
825 // Don't continue before the applyChanges is done!
826}
827
828void KMComposeWin::slotContinueAutoSave()
829{
830 disconnect( this, TQ_SIGNAL( applyChangesDone( bool ) ),
831 this, TQ_SLOT( slotContinueAutoSave() ) );
832
833 // Ok, it's done now - continue dead letter saving
834 if ( mComposedMessages.isEmpty() ) {
835 kdDebug(5006) << "Composing the message failed." << endl;
836 return;
837 }
838 KMMessage *msg = mComposedMessages.first();
839 if ( !msg ) // a bit of extra defensiveness
840 return;
841
842 kdDebug(5006) << k_funcinfo << "opening autoSaveFile " << mAutoSaveFilename
843 << endl;
844 const TQString filename =
845 KMKernel::localDataPath() + "autosave/cur/" + mAutoSaveFilename;
846 KSaveFile autoSaveFile( filename, 0600 );
847 int status = autoSaveFile.status();
848 kdDebug(5006) << k_funcinfo << "autoSaveFile.status() = " << status << endl;
849 if ( status == 0 ) { // no error
850 kdDebug(5006) << "autosaving message in " << filename << endl;
851 int fd = autoSaveFile.handle();
852 const DwString& msgStr = msg->asDwString();
853 if ( ::write( fd, msgStr.data(), msgStr.length() ) == -1 )
854 status = errno;
855 }
856 if ( status == 0 ) {
857 kdDebug(5006) << k_funcinfo << "closing autoSaveFile" << endl;
858 autoSaveFile.close();
859 mLastAutoSaveErrno = 0;
860 }
861 else {
862 kdDebug(5006) << k_funcinfo << "autosaving failed" << endl;
863 autoSaveFile.abort();
864 if ( status != mLastAutoSaveErrno ) {
865 // don't show the same error message twice
866 KMessageBox::queuedMessageBox( 0, KMessageBox::Sorry,
867 i18n("Autosaving the message as %1 "
868 "failed.\n"
869 "Reason: %2" )
870 .arg( filename, strerror( status ) ),
871 i18n("Autosaving Failed") );
872 mLastAutoSaveErrno = status;
873 }
874 }
875
876 if ( autoSaveInterval() > 0 )
877 updateAutoSave();
878}
879
880//-----------------------------------------------------------------------------
881void KMComposeWin::slotView(void)
882{
883 if (!mDone)
884 return; // otherwise called from rethinkFields during the construction
885 // which is not the intended behavior
886 int id;
887
888 //This sucks awfully, but no, I cannot get an activated(int id) from
889 // actionContainer()
890 if (!sender()->isA("TDEToggleAction"))
891 return;
892 TDEToggleAction *act = (TDEToggleAction *) sender();
893
894 if (act == mAllFieldsAction)
895 id = 0;
896 else if (act == mIdentityAction)
897 id = HDR_IDENTITY;
898 else if (act == mTransportAction)
899 id = HDR_TRANSPORT;
900 else if (act == mFromAction)
901 id = HDR_FROM;
902 else if (act == mReplyToAction)
903 id = HDR_REPLY_TO;
904 else if (act == mToAction)
905 id = HDR_TO;
906 else if (act == mCcAction)
907 id = HDR_CC;
908 else if (act == mBccAction)
909 id = HDR_BCC;
910 else if (act == mSubjectAction)
911 id = HDR_SUBJECT;
912 else if (act == mFccAction)
913 id = HDR_FCC;
914 else if ( act == mDictionaryAction )
915 id = HDR_DICTIONARY;
916 else
917 {
918 id = 0;
919 kdDebug(5006) << "Something is wrong (Oh, yeah?)" << endl;
920 return;
921 }
922
923 // sanders There's a bug here this logic doesn't work if no
924 // fields are shown and then show all fields is selected.
925 // Instead of all fields being shown none are.
926 if (!act->isChecked())
927 {
928 // hide header
929 if (id > 0) mShowHeaders = mShowHeaders & ~id;
930 else mShowHeaders = abs(mShowHeaders);
931 }
932 else
933 {
934 // show header
935 if (id > 0) mShowHeaders |= id;
936 else mShowHeaders = -abs(mShowHeaders);
937 }
938 rethinkFields(true);
939}
940
941int KMComposeWin::calcColumnWidth(int which, long allShowing, int width)
942{
943 if ( (allShowing & which) == 0 )
944 return width;
945
946 TQLabel *w;
947 if ( which == HDR_IDENTITY )
948 w = mLblIdentity;
949 else if ( which == HDR_DICTIONARY )
950 w = mDictionaryLabel;
951 else if ( which == HDR_FCC )
952 w = mLblFcc;
953 else if ( which == HDR_TRANSPORT )
954 w = mLblTransport;
955 else if ( which == HDR_FROM )
956 w = mLblFrom;
957 else if ( which == HDR_REPLY_TO )
958 w = mLblReplyTo;
959 else if ( which == HDR_SUBJECT )
960 w = mLblSubject;
961 else
962 return width;
963
964 w->setBuddy( mEditor ); // set dummy so we don't calculate width of '&' for this label.
965 w->adjustSize();
966 w->show();
967 return TQMAX( width, w->sizeHint().width() );
968}
969
970void KMComposeWin::rethinkFields(bool fromSlot)
971{
972 //This sucks even more but again no ids. sorry (sven)
973 int mask, row, numRows;
974 long showHeaders;
975
976 if (mShowHeaders < 0)
977 showHeaders = HDR_ALL;
978 else
979 showHeaders = mShowHeaders;
980
981 for (mask=1,mNumHeaders=0; mask<=showHeaders; mask<<=1)
982 if ((showHeaders&mask) != 0) mNumHeaders++;
983
984 numRows = mNumHeaders + 1;
985
986 delete mGrid;
987
988 mGrid = new TQGridLayout( mHeadersArea, numRows, 3, KDialogBase::marginHint()/2, KDialogBase::spacingHint());
989 mGrid->setColStretch(0, 1);
990 mGrid->setColStretch(1, 100);
991 mGrid->setColStretch(2, 1);
992 mGrid->setRowStretch( mNumHeaders + 1, 100 );
993
994 row = 0;
995 kdDebug(5006) << "KMComposeWin::rethinkFields" << endl;
996 if (mRecipientsEditor)
997 mLabelWidth = mRecipientsEditor->setFirstColumnWidth( 0 );
998 mLabelWidth = calcColumnWidth( HDR_IDENTITY, showHeaders, mLabelWidth );
999 mLabelWidth = calcColumnWidth( HDR_DICTIONARY, showHeaders, mLabelWidth );
1000 mLabelWidth = calcColumnWidth( HDR_FCC, showHeaders, mLabelWidth );
1001 mLabelWidth = calcColumnWidth( HDR_TRANSPORT, showHeaders, mLabelWidth );
1002 mLabelWidth = calcColumnWidth( HDR_FROM, showHeaders, mLabelWidth );
1003 mLabelWidth = calcColumnWidth( HDR_REPLY_TO, showHeaders, mLabelWidth );
1004 mLabelWidth = calcColumnWidth( HDR_SUBJECT, showHeaders, mLabelWidth );
1005
1006 if (!fromSlot) mAllFieldsAction->setChecked(showHeaders==HDR_ALL);
1007
1008 if (!fromSlot) mIdentityAction->setChecked(abs(mShowHeaders)&HDR_IDENTITY);
1009 rethinkHeaderLine(showHeaders,HDR_IDENTITY, row,
1010 mLblIdentity, mIdentity, mBtnIdentity);
1011
1012 if (!fromSlot) mDictionaryAction->setChecked(abs(mShowHeaders)&HDR_DICTIONARY);
1013 rethinkHeaderLine(showHeaders,HDR_DICTIONARY, row,
1014 mDictionaryLabel, mDictionaryCombo, mBtnDictionary );
1015
1016 if (!fromSlot) mFccAction->setChecked(abs(mShowHeaders)&HDR_FCC);
1017 rethinkHeaderLine(showHeaders,HDR_FCC, row,
1018 mLblFcc, mFcc, mBtnFcc);
1019
1020 if (!fromSlot) mTransportAction->setChecked(abs(mShowHeaders)&HDR_TRANSPORT);
1021 rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row,
1022 mLblTransport, mTransport, mBtnTransport);
1023
1024 if (!fromSlot) mFromAction->setChecked(abs(mShowHeaders)&HDR_FROM);
1025 rethinkHeaderLine(showHeaders,HDR_FROM, row,
1026 mLblFrom, mEdtFrom /*, mBtnFrom */ );
1027
1028 TQWidget *prevFocus = mEdtFrom;
1029
1030 if (!fromSlot) mReplyToAction->setChecked(abs(mShowHeaders)&HDR_REPLY_TO);
1031 rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,
1032 mLblReplyTo, mEdtReplyTo, 0);
1033 if ( showHeaders & HDR_REPLY_TO ) {
1034 prevFocus = connectFocusMoving( prevFocus, mEdtReplyTo );
1035 }
1036
1037 if ( mClassicalRecipients ) {
1038 if (!fromSlot) mToAction->setChecked(abs(mShowHeaders)&HDR_TO);
1039 rethinkHeaderLine(showHeaders, HDR_TO, row,
1040 mLblTo, mEdtTo, mBtnTo,
1041 i18n("Primary Recipients"),
1042 i18n("<qt>The email addresses you put "
1043 "in this field receive a copy of the email.</qt>"));
1044 if ( showHeaders & HDR_TO ) {
1045 prevFocus = connectFocusMoving( prevFocus, mEdtTo );
1046 }
1047
1048 if (!fromSlot) mCcAction->setChecked(abs(mShowHeaders)&HDR_CC);
1049 rethinkHeaderLine(showHeaders, HDR_CC, row,
1050 mLblCc, mEdtCc, mBtnCc,
1051 i18n("Additional Recipients"),
1052 i18n("<qt>The email addresses you put "
1053 "in this field receive a copy of the email. "
1054 "Technically it is the same thing as putting all the "
1055 "addresses in the <b>To:</b> field but differs in "
1056 "that it usually symbolises the receiver of the "
1057 "Carbon Copy (CC) is a listener, not the main "
1058 "recipient.</qt>"));
1059 if ( showHeaders & HDR_CC ) {
1060 prevFocus = connectFocusMoving( prevFocus, mEdtCc );
1061 }
1062
1063 if (!fromSlot) mBccAction->setChecked(abs(mShowHeaders)&HDR_BCC);
1064 rethinkHeaderLine(showHeaders,HDR_BCC, row,
1065 mLblBcc, mEdtBcc, mBtnBcc,
1066 i18n("Hidden Recipients"),
1067 i18n("<qt>Essentially the same thing "
1068 "as the <b>Copy To:</b> field but differs in that "
1069 "all other recipients do not see who receives a "
1070 "blind copy.</qt>"));
1071 if ( showHeaders & HDR_BCC ) {
1072 prevFocus = connectFocusMoving( prevFocus, mEdtBcc );
1073 }
1074 } else {
1075 mGrid->addMultiCellWidget( mRecipientsEditor, row, row, 0, 2 );
1076 ++row;
1077
1078 if ( showHeaders & HDR_REPLY_TO ) {
1079 connect( mEdtReplyTo, TQ_SIGNAL( focusDown() ), mRecipientsEditor,
1080 TQ_SLOT( setFocusTop() ) );
1081 } else {
1082 connect( mEdtFrom, TQ_SIGNAL( focusDown() ), mRecipientsEditor,
1083 TQ_SLOT( setFocusTop() ) );
1084 }
1085 if ( showHeaders & HDR_REPLY_TO ) {
1086 connect( mRecipientsEditor, TQ_SIGNAL( focusUp() ), mEdtReplyTo, TQ_SLOT( setFocus() ) );
1087 } else {
1088 connect( mRecipientsEditor, TQ_SIGNAL( focusUp() ), mEdtFrom, TQ_SLOT( setFocus() ) );
1089 }
1090
1091 connect( mRecipientsEditor, TQ_SIGNAL( focusDown() ), mEdtSubject,
1092 TQ_SLOT( setFocus() ) );
1093 connect( mEdtSubject, TQ_SIGNAL( focusUp() ), mRecipientsEditor,
1094 TQ_SLOT( setFocusBottom() ) );
1095
1096 prevFocus = mRecipientsEditor;
1097 }
1098 if (!fromSlot) mSubjectAction->setChecked(abs(mShowHeaders)&HDR_SUBJECT);
1099 rethinkHeaderLine(showHeaders,HDR_SUBJECT, row,
1100 mLblSubject, mEdtSubject);
1101 connectFocusMoving( mEdtSubject, mEditor );
1102
1103 assert(row<=mNumHeaders);
1104
1105
1106 if( !mAtmList.isEmpty() )
1107 mAtmListView->show();
1108 else
1109 mAtmListView->hide();
1110 resize(this->size());
1111 repaint();
1112
1113 mHeadersArea->setMaximumHeight( mHeadersArea->sizeHint().height() );
1114 mGrid->activate();
1115 mHeadersArea->show();
1116
1117 slotUpdateAttachActions();
1118 mIdentityAction->setEnabled(!mAllFieldsAction->isChecked());
1119 mDictionaryAction->setEnabled( !mAllFieldsAction->isChecked() );
1120 mTransportAction->setEnabled(!mAllFieldsAction->isChecked());
1121 mFromAction->setEnabled(!mAllFieldsAction->isChecked());
1122 if ( mReplyToAction ) mReplyToAction->setEnabled(!mAllFieldsAction->isChecked());
1123 if ( mToAction ) mToAction->setEnabled(!mAllFieldsAction->isChecked());
1124 if ( mCcAction ) mCcAction->setEnabled(!mAllFieldsAction->isChecked());
1125 if ( mBccAction ) mBccAction->setEnabled(!mAllFieldsAction->isChecked());
1126 mFccAction->setEnabled(!mAllFieldsAction->isChecked());
1127 mSubjectAction->setEnabled(!mAllFieldsAction->isChecked());
1128 if (mRecipientsEditor)
1129 mRecipientsEditor->setFirstColumnWidth( mLabelWidth );
1130}
1131
1132TQWidget *KMComposeWin::connectFocusMoving( TQWidget *prev, TQWidget *next )
1133{
1134 connect( prev, TQ_SIGNAL( focusDown() ), next, TQ_SLOT( setFocus() ) );
1135 connect( next, TQ_SIGNAL( focusUp() ), prev, TQ_SLOT( setFocus() ) );
1136
1137 return next;
1138}
1139
1140//-----------------------------------------------------------------------------
1141void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
1142 TQLabel* aLbl,
1143 TQLineEdit* aEdt, TQPushButton* aBtn,
1144 const TQString &toolTip, const TQString &whatsThis )
1145{
1146 if (aValue & aMask)
1147 {
1148 if ( !toolTip.isEmpty() )
1149 TQToolTip::add( aLbl, toolTip );
1150 if ( !whatsThis.isEmpty() )
1151 TQWhatsThis::add( aLbl, whatsThis );
1152 aLbl->setFixedWidth( mLabelWidth );
1153 aLbl->setBuddy(aEdt);
1154 mGrid->addWidget(aLbl, aRow, 0);
1155 aEdt->setBackgroundColor( mBackColor );
1156 aEdt->show();
1157
1158 if (aBtn) {
1159 mGrid->addWidget(aEdt, aRow, 1);
1160
1161 mGrid->addWidget(aBtn, aRow, 2);
1162 aBtn->show();
1163 } else {
1164 mGrid->addMultiCellWidget(aEdt, aRow, aRow, 1, 2 );
1165 }
1166 aRow++;
1167 }
1168 else
1169 {
1170 aLbl->hide();
1171 aEdt->hide();
1172 if (aBtn) aBtn->hide();
1173 }
1174}
1175
1176//-----------------------------------------------------------------------------
1177void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
1178 TQLabel* aLbl,
1179 TQComboBox* aCbx, TQCheckBox* aChk)
1180{
1181 if (aValue & aMask)
1182 {
1183 aLbl->adjustSize();
1184 aLbl->resize((int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
1185 aLbl->setMinimumSize(aLbl->size());
1186 aLbl->show();
1187 aLbl->setBuddy(aCbx);
1188 mGrid->addWidget(aLbl, aRow, 0);
1189 aCbx->show();
1190 aCbx->setMinimumSize(100, aLbl->height()+2);
1191
1192 mGrid->addWidget(aCbx, aRow, 1);
1193 if ( aChk ) {
1194 mGrid->addWidget(aChk, aRow, 2);
1195 aChk->setFixedSize(aChk->sizeHint().width(), aLbl->height());
1196 aChk->show();
1197 }
1198 aRow++;
1199 }
1200 else
1201 {
1202 aLbl->hide();
1203 aCbx->hide();
1204 if ( aChk )
1205 aChk->hide();
1206 }
1207}
1208
1209//-----------------------------------------------------------------------------
1210void KMComposeWin::getTransportMenu()
1211{
1212 TQStringList availTransports;
1213
1214 mActNowMenu->clear();
1215 mActLaterMenu->clear();
1216 availTransports = KMail::TransportManager::transportNames();
1217 TQStringList::Iterator it;
1218 int id = 0;
1219 for(it = availTransports.begin(); it != availTransports.end() ; ++it, id++)
1220 {
1221 mActNowMenu->insertItem((*it).replace("&", "&&"), id);
1222 mActLaterMenu->insertItem((*it).replace("&", "&&"), id);
1223 }
1224}
1225
1226
1227//-----------------------------------------------------------------------------
1228void KMComposeWin::setupActions(void)
1229{
1230 TDEActionMenu *actActionNowMenu, *actActionLaterMenu;
1231
1232 if (kmkernel->msgSender()->sendImmediate()) //default == send now?
1233 {
1234 //default = send now, alternative = queue
1235 ( void ) new TDEAction( i18n("&Send Mail"), "mail-send", CTRL+Key_Return,
1236 this, TQ_SLOT(slotSendNow()), actionCollection(),"send_default");
1237
1238 // FIXME: change to mail_send_via icon when this exits.
1239 actActionNowMenu = new TDEActionMenu (i18n("&Send Mail Via"), "mail-send",
1240 actionCollection(), "send_default_via" );
1241
1242 (void) new TDEAction (i18n("Send &Later"), "queue", 0, this,
1243 TQ_SLOT(slotSendLater()), actionCollection(),"send_alternative");
1244 actActionLaterMenu = new TDEActionMenu (i18n("Send &Later Via"), "queue",
1245 actionCollection(), "send_alternative_via" );
1246
1247 }
1248 else //no, default = send later
1249 {
1250 //default = queue, alternative = send now
1251 (void) new TDEAction (i18n("Send &Later"), "queue",
1252 CTRL+Key_Return,
1253 this, TQ_SLOT(slotSendLater()), actionCollection(),"send_default");
1254 actActionLaterMenu = new TDEActionMenu (i18n("Send &Later Via"), "queue",
1255 actionCollection(), "send_default_via" );
1256
1257 ( void ) new TDEAction( i18n("&Send Mail"), "mail-send", 0,
1258 this, TQ_SLOT(slotSendNow()), actionCollection(),"send_alternative");
1259
1260 // FIXME: change to mail_send_via icon when this exits.
1261 actActionNowMenu = new TDEActionMenu (i18n("&Send Mail Via"), "mail-send",
1262 actionCollection(), "send_alternative_via" );
1263
1264 }
1265
1266 // needed for sending "default transport"
1267 actActionNowMenu->setDelayed(true);
1268 actActionLaterMenu->setDelayed(true);
1269
1270 connect( actActionNowMenu, TQ_SIGNAL( activated() ), this,
1271 TQ_SLOT( slotSendNow() ) );
1272 connect( actActionLaterMenu, TQ_SIGNAL( activated() ), this,
1273 TQ_SLOT( slotSendLater() ) );
1274
1275
1276 mActNowMenu = actActionNowMenu->popupMenu();
1277 mActLaterMenu = actActionLaterMenu->popupMenu();
1278
1279 connect( mActNowMenu, TQ_SIGNAL( activated( int ) ), this,
1280 TQ_SLOT( slotSendNowVia( int ) ) );
1281 connect( mActNowMenu, TQ_SIGNAL( aboutToShow() ), this,
1282 TQ_SLOT( getTransportMenu() ) );
1283
1284 connect( mActLaterMenu, TQ_SIGNAL( activated( int ) ), this,
1285 TQ_SLOT( slotSendLaterVia( int ) ) );
1286 connect( mActLaterMenu, TQ_SIGNAL( aboutToShow() ), this,
1287 TQ_SLOT( getTransportMenu() ) );
1288
1289
1290
1291
1292 (void) new TDEAction (i18n("Save as &Draft"), "document-save", 0,
1293 this, TQ_SLOT(slotSaveDraft()),
1294 actionCollection(), "save_in_drafts");
1295 (void) new TDEAction (i18n("Save as &Template"), "document-save", 0,
1296 this, TQ_SLOT(slotSaveTemplate()),
1297 actionCollection(), "save_in_templates");
1298 (void) new TDEAction (i18n("&Insert File..."), "document-open", 0,
1299 this, TQ_SLOT(slotInsertFile()),
1300 actionCollection(), "insert_file");
1301 mRecentAction = new TDERecentFilesAction (i18n("&Insert File Recent"),
1302 "document-open", 0,
1303 this, TQ_SLOT(slotInsertRecentFile(const KURL&)),
1304 actionCollection(), "insert_file_recent");
1305
1306 mRecentAction->loadEntries( KMKernel::config() );
1307
1308 (void) new TDEAction (i18n("&Address Book"), "contents",0,
1309 this, TQ_SLOT(slotAddrBook()),
1310 actionCollection(), "addressbook");
1311 (void) new TDEAction (i18n("&New Composer"), "mail-message-new",
1312 TDEStdAccel::shortcut(TDEStdAccel::New),
1313 this, TQ_SLOT(slotNewComposer()),
1314 actionCollection(), "new_composer");
1315 (void) new TDEAction (i18n("New Main &Window"), "window-new", 0,
1316 this, TQ_SLOT(slotNewMailReader()),
1317 actionCollection(), "open_mailreader");
1318
1319 if ( !mClassicalRecipients ) {
1320 new TDEAction( i18n("Select &Recipients..."), CTRL + Key_L, mRecipientsEditor,
1321 TQ_SLOT( selectRecipients() ), actionCollection(), "select_recipients" );
1322 new TDEAction( i18n("Save &Distribution List..."), 0, mRecipientsEditor,
1323 TQ_SLOT( saveDistributionList() ), actionCollection(),
1324 "save_distribution_list" );
1325 }
1326
1327 //KStdAction::save(this, TQ_SLOT(), actionCollection(), "save_message");
1328 KStdAction::print (this, TQ_SLOT(slotPrint()), actionCollection());
1329 KStdAction::close (this, TQ_SLOT(slotClose()), actionCollection());
1330
1331 KStdAction::undo (this, TQ_SLOT(slotUndo()), actionCollection());
1332 KStdAction::redo (this, TQ_SLOT(slotRedo()), actionCollection());
1333 KStdAction::cut (this, TQ_SLOT(slotCut()), actionCollection());
1334 KStdAction::copy (this, TQ_SLOT(slotCopy()), actionCollection());
1335 KStdAction::pasteText (this, TQ_SLOT(slotPasteClipboard()), actionCollection());
1336 KStdAction::selectAll (this, TQ_SLOT(slotMarkAll()), actionCollection());
1337
1338 KStdAction::find (this, TQ_SLOT(slotFind()), actionCollection());
1339 KStdAction::findNext(this, TQ_SLOT(slotSearchAgain()), actionCollection());
1340
1341 KStdAction::replace (this, TQ_SLOT(slotReplace()), actionCollection());
1342 KStdAction::spelling (this, TQ_SLOT(slotSpellcheck()), actionCollection(), "tools-check-spelling");
1343
1344 mPasteQuotation = new TDEAction (i18n("Pa&ste as Quotation"),0,this,TQ_SLOT( slotPasteClipboardAsQuotation()),
1345 actionCollection(), "paste_quoted");
1346
1347 (void) new TDEAction (i18n("Paste as Attac&hment"),0,this,TQ_SLOT( slotPasteClipboardAsAttachment()),
1348 actionCollection(), "paste_att");
1349
1350 TDEAction * addq = new TDEAction(i18n("Add &Quote Characters"), 0, this,
1351 TQ_SLOT(slotAddQuotes()), actionCollection(), "tools_quote");
1352 connect( mEditor, TQ_SIGNAL(selectionAvailable(bool)),
1353 addq, TQ_SLOT(setEnabled(bool)) );
1354
1355 TDEAction * remq = new TDEAction(i18n("Re&move Quote Characters"), 0, this,
1356 TQ_SLOT(slotRemoveQuotes()), actionCollection(), "tools_unquote");
1357 connect( mEditor, TQ_SIGNAL(selectionAvailable(bool)),
1358 remq, TQ_SLOT(setEnabled(bool)) );
1359
1360
1361 (void) new TDEAction (i18n("Cl&ean Spaces"), 0, this, TQ_SLOT(slotCleanSpace()),
1362 actionCollection(), "clean_spaces");
1363
1364 mFixedFontAction = new TDEToggleAction( i18n("Use Fi&xed Font"), 0, this,
1365 TQ_SLOT(slotUpdateFont()), actionCollection(), "toggle_fixedfont" );
1366 mFixedFontAction->setChecked( GlobalSettings::self()->useFixedFont() );
1367
1368 //these are checkable!!!
1369 mUrgentAction = new TDEToggleAction (i18n("&Urgent"), 0,
1370 actionCollection(),
1371 "urgent");
1372 mRequestMDNAction = new TDEToggleAction ( i18n("&Request Disposition Notification"), 0,
1373 actionCollection(),
1374 "options_request_mdn");
1375 mRequestMDNAction->setChecked(GlobalSettings::self()->requestMDN());
1376 //----- Message-Encoding Submenu
1377 mEncodingAction = new TDESelectAction( i18n( "Se&t Encoding" ), "charset",
1378 0, this, TQ_SLOT(slotSetCharset() ),
1379 actionCollection(), "charsets" );
1380 mWordWrapAction = new TDEToggleAction (i18n("&Wordwrap"), 0,
1381 actionCollection(), "wordwrap");
1382 mWordWrapAction->setChecked(GlobalSettings::self()->wordWrap());
1383 connect(mWordWrapAction, TQ_SIGNAL(toggled(bool)), TQ_SLOT(slotWordWrapToggled(bool)));
1384
1385 mSnippetAction = new TDEToggleAction ( i18n("&Snippets"), 0,
1386 actionCollection(), "snippets");
1387 connect(mSnippetAction, TQ_SIGNAL(toggled(bool)), mSnippetWidget, TQ_SLOT(setShown(bool)) );
1388 mSnippetAction->setChecked( GlobalSettings::self()->showSnippetManager() );
1389
1390 mAutoSpellCheckingAction =
1391 new TDEToggleAction( i18n( "&Automatic Spellchecking" ), "tools-check-spelling", 0,
1392 actionCollection(), "options_auto_spellchecking" );
1393 const bool spellChecking = GlobalSettings::self()->autoSpellChecking();
1394 mAutoSpellCheckingAction->setEnabled( !GlobalSettings::self()->useExternalEditor() );
1395 mAutoSpellCheckingAction->setChecked( !GlobalSettings::self()->useExternalEditor() && spellChecking );
1396 slotAutoSpellCheckingToggled( !GlobalSettings::self()->useExternalEditor() && spellChecking );
1397 connect( mAutoSpellCheckingAction, TQ_SIGNAL( toggled( bool ) ),
1398 this, TQ_SLOT( slotAutoSpellCheckingToggled( bool ) ) );
1399
1400 TQStringList encodings = KMMsgBase::supportedEncodings(true);
1401 encodings.prepend( i18n("Auto-Detect"));
1402 mEncodingAction->setItems( encodings );
1403 mEncodingAction->setCurrentItem( -1 );
1404
1405 //these are checkable!!!
1406 markupAction = new TDEToggleAction (i18n("Formatting (HTML)"), 0, this,
1407 TQ_SLOT(slotToggleMarkup()),
1408 actionCollection(), "html");
1409
1410 mAllFieldsAction = new TDEToggleAction (i18n("&All Fields"), 0, this,
1411 TQ_SLOT(slotView()),
1412 actionCollection(), "show_all_fields");
1413 mIdentityAction = new TDEToggleAction (i18n("&Identity"), 0, this,
1414 TQ_SLOT(slotView()),
1415 actionCollection(), "show_identity");
1416 mDictionaryAction = new TDEToggleAction (i18n("&Dictionary"), 0, this,
1417 TQ_SLOT(slotView()),
1418 actionCollection(), "show_dictionary");
1419 mFccAction = new TDEToggleAction (i18n("&Sent-Mail Folder"), 0, this,
1420 TQ_SLOT(slotView()),
1421 actionCollection(), "show_fcc");
1422 mTransportAction = new TDEToggleAction (i18n("&Mail Transport"), 0, this,
1423 TQ_SLOT(slotView()),
1424 actionCollection(), "show_transport");
1425 mFromAction = new TDEToggleAction (i18n("&From"), 0, this,
1426 TQ_SLOT(slotView()),
1427 actionCollection(), "show_from");
1428 mReplyToAction = new TDEToggleAction (i18n("&Reply To"), 0, this,
1429 TQ_SLOT(slotView()),
1430 actionCollection(), "show_reply_to");
1431 if ( mClassicalRecipients ) {
1432 mToAction = new TDEToggleAction (i18n("&To"), 0, this,
1433 TQ_SLOT(slotView()),
1434 actionCollection(), "show_to");
1435 mCcAction = new TDEToggleAction (i18n("&CC"), 0, this,
1436 TQ_SLOT(slotView()),
1437 actionCollection(), "show_cc");
1438 mBccAction = new TDEToggleAction (i18n("&BCC"), 0, this,
1439 TQ_SLOT(slotView()),
1440 actionCollection(), "show_bcc");
1441 }
1442 mSubjectAction = new TDEToggleAction (i18n("S&ubject"), 0, this,
1443 TQ_SLOT(slotView()),
1444 actionCollection(), "show_subject");
1445 //end of checkable
1446
1447 mAppendSignatureAction = new TDEAction (i18n("Append S&ignature"), 0, this,
1448 TQ_SLOT(slotAppendSignature()),
1449 actionCollection(), "append_signature");
1450 mPrependSignatureAction = new TDEAction (i18n("Prepend S&ignature"), 0, this,
1451 TQ_SLOT(slotPrependSignature()),
1452 actionCollection(), "prepend_signature");
1453
1454 mInsertSignatureAction = new TDEAction (i18n("Insert Signature At C&ursor Position"), "edit", 0, this,
1455 TQ_SLOT(slotInsertSignatureAtCursor()),
1456 actionCollection(), "insert_signature_at_cursor_position");
1457
1458 mAttachPK = new TDEAction (i18n("Attach &Public Key..."), 0, this,
1459 TQ_SLOT(slotInsertPublicKey()),
1460 actionCollection(), "attach_public_key");
1461 mAttachMPK = new TDEAction (i18n("Attach &My Public Key"), 0, this,
1462 TQ_SLOT(slotInsertMyPublicKey()),
1463 actionCollection(), "attach_my_public_key");
1464 (void) new TDEAction (i18n("&Attach File..."), "attach",
1465 0, this, TQ_SLOT(slotAttachFile()),
1466 actionCollection(), "attach");
1467 mAttachRemoveAction = new TDEAction (i18n("&Remove Attachment"), 0, this,
1468 TQ_SLOT(slotAttachRemove()),
1469 actionCollection(), "remove");
1470 mAttachSaveAction = new TDEAction (i18n("&Save Attachment As..."), "document-save",0,
1471 this, TQ_SLOT(slotAttachSave()),
1472 actionCollection(), "attach_save");
1473 mAttachPropertiesAction = new TDEAction (i18n("Attachment Pr&operties"), 0, this,
1474 TQ_SLOT(slotAttachProperties()),
1475 actionCollection(), "attach_properties");
1476
1477 setStandardToolBarMenuEnabled(true);
1478
1479 KStdAction::keyBindings(this, TQ_SLOT(slotEditKeys()), actionCollection());
1480 KStdAction::configureToolbars(this, TQ_SLOT(slotEditToolbars()), actionCollection());
1481 KStdAction::preferences(kmkernel, TQ_SLOT(slotShowConfigurationDialog()), actionCollection());
1482
1483 (void) new TDEAction (i18n("&Spellchecker..."), 0, this, TQ_SLOT(slotSpellcheckConfig()),
1484 actionCollection(), "setup_spellchecker");
1485
1486 if ( Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) ) {
1487 TDEToggleAction * a = new TDEToggleAction( i18n( "Encrypt Message with Chiasmus..." ),
1488 "chidecrypted", 0, actionCollection(),
1489 "encrypt_message_chiasmus" );
1490 a->setCheckedState( KGuiItem( i18n( "Encrypt Message with Chiasmus..." ), "chiencrypted" ) );
1491 mEncryptChiasmusAction = a;
1492 connect( mEncryptChiasmusAction, TQ_SIGNAL(toggled(bool)),
1493 this, TQ_SLOT(slotEncryptChiasmusToggled(bool)) );
1494 } else {
1495 mEncryptChiasmusAction = 0;
1496 }
1497
1498 mEncryptAction = new TDEToggleAction (i18n("&Encrypt Message"),
1499 "decrypted", 0,
1500 actionCollection(), "encrypt_message");
1501 mSignAction = new TDEToggleAction (i18n("&Sign Message"),
1502 "signature", 0,
1503 actionCollection(), "sign_message");
1504 // get PGP user id for the chosen identity
1505 const KPIM::Identity & ident =
1506 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
1507 // PENDING(marc): check the uses of this member and split it into
1508 // smime/openpgp and or enc/sign, if necessary:
1509 mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
1510 mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
1511
1512 mLastEncryptActionState = false;
1513 mLastSignActionState = GlobalSettings::self()->pgpAutoSign();
1514
1515 // "Attach public key" is only possible if OpenPGP support is available:
1516 mAttachPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() );
1517
1518 // "Attach my public key" is only possible if OpenPGP support is
1519 // available and the user specified his key for the current identity:
1520 mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
1521 !ident.pgpEncryptionKey().isEmpty() );
1522
1523 if ( !Kleo::CryptoBackendFactory::instance()->openpgp() && !Kleo::CryptoBackendFactory::instance()->smime() ) {
1524 // no crypto whatsoever
1525 mEncryptAction->setEnabled( false );
1526 setEncryption( false );
1527 mSignAction->setEnabled( false );
1528 setSigning( false );
1529 } else {
1530 const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
1531 && !ident.pgpSigningKey().isEmpty();
1532 const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
1533 && !ident.smimeSigningKey().isEmpty();
1534
1535 setEncryption( false );
1536 setSigning( ( canOpenPGPSign || canSMIMESign ) && GlobalSettings::self()->pgpAutoSign() );
1537 }
1538
1539 connect(mEncryptAction, TQ_SIGNAL(toggled(bool)),
1540 TQ_SLOT(slotEncryptToggled( bool )));
1541 connect(mSignAction, TQ_SIGNAL(toggled(bool)),
1542 TQ_SLOT(slotSignToggled( bool )));
1543
1544 TQStringList l;
1545 for ( int i = 0 ; i < numCryptoMessageFormats ; ++i )
1546 l.push_back( Kleo::cryptoMessageFormatToLabel( cryptoMessageFormats[i] ) );
1547
1548 mCryptoModuleAction = new TDESelectAction( i18n( "&Cryptographic Message Format" ), 0,
1549 this, TQ_SLOT(slotSelectCryptoModule()),
1550 actionCollection(), "options_select_crypto" );
1551 mCryptoModuleAction->setItems( l );
1552 mCryptoModuleAction->setCurrentItem( format2cb( ident.preferredCryptoMessageFormat() ) );
1553 mCryptoModuleAction->setToolTip( i18n( "Select a cryptographic format for this message" ) );
1554 slotSelectCryptoModule( true /* initialize */ );
1555
1556 TQStringList styleItems;
1557 styleItems << i18n( "Standard" );
1558 styleItems << i18n( "Bulleted List (Disc)" );
1559 styleItems << i18n( "Bulleted List (Circle)" );
1560 styleItems << i18n( "Bulleted List (Square)" );
1561 styleItems << i18n( "Ordered List (Decimal)" );
1562 styleItems << i18n( "Ordered List (Alpha lower)" );
1563 styleItems << i18n( "Ordered List (Alpha upper)" );
1564
1565 listAction = new TDESelectAction( i18n( "Select Style" ), 0, actionCollection(),
1566 "text_list" );
1567 listAction->setItems( styleItems );
1568 listAction->setToolTip( i18n( "Select a list style" ) );
1569 connect( listAction, TQ_SIGNAL( activated( const TQString& ) ),
1570 TQ_SLOT( slotListAction( const TQString& ) ) );
1571 fontAction = new TDEFontAction( "Select Font", 0, actionCollection(),
1572 "text_font" );
1573 fontAction->setToolTip( i18n( "Select a font" ) );
1574 connect( fontAction, TQ_SIGNAL( activated( const TQString& ) ),
1575 TQ_SLOT( slotFontAction( const TQString& ) ) );
1576 fontSizeAction = new TDEFontSizeAction( "Select Size", 0, actionCollection(),
1577 "text_size" );
1578 fontSizeAction->setToolTip( i18n( "Select a font size" ) );
1579 connect( fontSizeAction, TQ_SIGNAL( fontSizeChanged( int ) ),
1580 TQ_SLOT( slotSizeAction( int ) ) );
1581
1582 alignLeftAction = new TDEToggleAction (i18n("Align Left"), "format-text-direction-ltr", 0,
1583 this, TQ_SLOT(slotAlignLeft()), actionCollection(),
1584 "align_left");
1585 alignLeftAction->setChecked( true );
1586 alignRightAction = new TDEToggleAction (i18n("Align Right"), "format-text-direction-rtl", 0,
1587 this, TQ_SLOT(slotAlignRight()), actionCollection(),
1588 "align_right");
1589 alignCenterAction = new TDEToggleAction (i18n("Align Center"), "text_center", 0,
1590 this, TQ_SLOT(slotAlignCenter()), actionCollection(),
1591 "align_center");
1592 textBoldAction = new TDEToggleAction( i18n("&Bold"), "format-text-bold", CTRL+Key_B,
1593 this, TQ_SLOT(slotTextBold()),
1594 actionCollection(), "format-text-bold");
1595 textItalicAction = new TDEToggleAction( i18n("&Italic"), "format-text-italic", CTRL+Key_I,
1596 this, TQ_SLOT(slotTextItalic()),
1597 actionCollection(), "format-text-italic");
1598 textUnderAction = new TDEToggleAction( i18n("&Underline"), "format-text-underline", CTRL+Key_U,
1599 this, TQ_SLOT(slotTextUnder()),
1600 actionCollection(), "format-text-underline");
1601 actionFormatReset = new TDEAction( i18n( "Reset Font Settings" ), "eraser", 0,
1602 this, TQ_SLOT( slotFormatReset() ),
1603 actionCollection(), "format_reset");
1604 actionFormatColor = new TDEAction( i18n( "Text Color..." ), "colorize", 0,
1605 this, TQ_SLOT( slotTextColor() ),
1606 actionCollection(), "format_color");
1607
1608 // editorFocusChanged(false);
1609 createGUI("kmcomposerui.rc");
1610
1611 connect( toolBar("htmlToolBar"), TQ_SIGNAL( visibilityChanged(bool) ),
1612 this, TQ_SLOT( htmlToolBarVisibilityChanged(bool) ) );
1613
1614 // In Kontact, this entry would read "Configure Kontact", but bring
1615 // up KMail's config dialog. That's sensible, though, so fix the label.
1616 TDEAction* configureAction = actionCollection()->action("options_configure" );
1617 if ( configureAction )
1618 configureAction->setText( i18n("Configure KMail..." ) );
1619}
1620
1621//-----------------------------------------------------------------------------
1622void KMComposeWin::setupStatusBar(void)
1623{
1624 statusBar()->insertItem("", 0, 1);
1625 statusBar()->setItemAlignment(0, AlignLeft | AlignVCenter);
1626
1627 statusBar()->insertItem(i18n( " Spellcheck: %1 ").arg( " " ), 3, 0, true );
1628 statusBar()->insertItem(i18n( " Column: %1 ").arg(" "), 2, 0, true);
1629 statusBar()->insertItem(i18n( " Line: %1 ").arg(" "), 1, 0, true);
1630}
1631
1632
1633//-----------------------------------------------------------------------------
1634void KMComposeWin::updateCursorPosition()
1635{
1636 int col,line;
1637 TQString temp;
1638 line = mEditor->currentLine();
1639 col = mEditor->currentColumn();
1640 temp = i18n(" Line: %1 ").arg(line+1);
1641 statusBar()->changeItem(temp,1);
1642 temp = i18n(" Column: %1 ").arg(col+1);
1643 statusBar()->changeItem(temp,2);
1644}
1645
1646
1647//-----------------------------------------------------------------------------
1648void KMComposeWin::setupEditor(void)
1649{
1650 //TQPopupMenu* menu;
1651 mEditor->setModified(false);
1652 TQFontMetrics fm(mBodyFont);
1653 mEditor->setTabStopWidth(fm.width(TQChar(' ')) * 8);
1654 //mEditor->setFocusPolicy(TQWidget::ClickFocus);
1655
1656 slotWordWrapToggled( GlobalSettings::self()->wordWrap() );
1657
1658 // Font setup
1659 slotUpdateFont();
1660
1661 /* installRBPopup() is broken in tdelibs, we should wait for
1662 the new klibtextedit (dnaber, 2002-01-01)
1663 menu = new TQPopupMenu(this);
1664 //#ifdef BROKEN
1665 menu->insertItem(i18n("Undo"),mEditor,
1666 TQ_SLOT(undo()), TDEStdAccel::shortcut(TDEStdAccel::Undo));
1667 menu->insertItem(i18n("Redo"),mEditor,
1668 TQ_SLOT(redo()), TDEStdAccel::shortcut(TDEStdAccel::Redo));
1669 menu->insertSeparator();
1670 //#endif //BROKEN
1671 menu->insertItem(i18n("Cut"), this, TQ_SLOT(slotCut()));
1672 menu->insertItem(i18n("Copy"), this, TQ_SLOT(slotCopy()));
1673 menu->insertItem(i18n("Paste"), this, TQ_SLOT(slotPasteClipboard()));
1674 menu->insertItem(i18n("Mark All"),this, TQ_SLOT(slotMarkAll()));
1675 menu->insertSeparator();
1676 menu->insertItem(i18n("Find..."), this, TQ_SLOT(slotFind()));
1677 menu->insertItem(i18n("Replace..."), this, TQ_SLOT(slotReplace()));
1678 menu->insertSeparator();
1679 menu->insertItem(i18n("Fixed Font Widths"), this, TQ_SLOT(slotUpdateFont()));
1680 mEditor->installRBPopup(menu);
1681 */
1682 updateCursorPosition();
1683 connect(mEditor,TQ_SIGNAL(CursorPositionChanged()),TQ_SLOT(updateCursorPosition()));
1684 connect( mEditor, TQ_SIGNAL( currentFontChanged( const TQFont & ) ),
1685 this, TQ_SLOT( fontChanged( const TQFont & ) ) );
1686 connect( mEditor, TQ_SIGNAL( currentAlignmentChanged( int ) ),
1687 this, TQ_SLOT( alignmentChanged( int ) ) );
1688
1689}
1690
1691
1692//-----------------------------------------------------------------------------
1693static TQString cleanedUpHeaderString( const TQString & s )
1694{
1695 // remove invalid characters from the header strings
1696 TQString res( s );
1697 res.replace( '\r', "" );
1698 res.replace( '\n', " " );
1699 return res.stripWhiteSpace();
1700}
1701
1702//-----------------------------------------------------------------------------
1703TQString KMComposeWin::subject() const
1704{
1705 return cleanedUpHeaderString( mEdtSubject->text() );
1706}
1707
1708//-----------------------------------------------------------------------------
1709TQString KMComposeWin::to() const
1710{
1711 if ( mEdtTo ) {
1712 return cleanedUpHeaderString( mEdtTo->text() );
1713 } else if ( mRecipientsEditor ) {
1714 return mRecipientsEditor->recipientString( Recipient::To );
1715 } else {
1716 return TQString();
1717 }
1718}
1719
1720//-----------------------------------------------------------------------------
1721TQString KMComposeWin::cc() const
1722{
1723 if ( mEdtCc && !mEdtCc->isHidden() ) {
1724 return cleanedUpHeaderString( mEdtCc->text() );
1725 } else if ( mRecipientsEditor ) {
1726 return mRecipientsEditor->recipientString( Recipient::Cc );
1727 } else {
1728 return TQString();
1729 }
1730}
1731
1732//-----------------------------------------------------------------------------
1733TQString KMComposeWin::bcc() const
1734{
1735 if ( mEdtBcc && !mEdtBcc->isHidden() ) {
1736 return cleanedUpHeaderString( mEdtBcc->text() );
1737 } else if ( mRecipientsEditor ) {
1738 return mRecipientsEditor->recipientString( Recipient::Bcc );
1739 } else {
1740 return TQString();
1741 }
1742}
1743
1744//-----------------------------------------------------------------------------
1745TQString KMComposeWin::from() const
1746{
1747 return cleanedUpHeaderString( mEdtFrom->text() );
1748}
1749
1750//-----------------------------------------------------------------------------
1751TQString KMComposeWin::replyTo() const
1752{
1753 if ( mEdtReplyTo ) {
1754 return cleanedUpHeaderString( mEdtReplyTo->text() );
1755 } else {
1756 return TQString();
1757 }
1758}
1759
1760//-----------------------------------------------------------------------------
1761void KMComposeWin::verifyWordWrapLengthIsAdequate(const TQString &body)
1762{
1763 int maxLineLength = 0;
1764 int curPos;
1765 int oldPos = 0;
1766 if (mEditor->TQTextEdit::wordWrap() == TQTextEdit::FixedColumnWidth) {
1767 for (curPos = 0; curPos < (int)body.length(); ++curPos)
1768 if (body[curPos] == '\n') {
1769 if ((curPos - oldPos) > maxLineLength)
1770 maxLineLength = curPos - oldPos;
1771 oldPos = curPos;
1772 }
1773 if ((curPos - oldPos) > maxLineLength)
1774 maxLineLength = curPos - oldPos;
1775 if (mEditor->wrapColumnOrWidth() < maxLineLength) // column
1776 mEditor->setWrapColumnOrWidth(maxLineLength);
1777 }
1778}
1779
1780//-----------------------------------------------------------------------------
1781void KMComposeWin::decryptOrStripOffCleartextSignature( TQCString& body )
1782{
1783 TQPtrList<Kpgp::Block> pgpBlocks;
1784 TQStrList nonPgpBlocks;
1785 if( Kpgp::Module::prepareMessageForDecryption( body,
1786 pgpBlocks, nonPgpBlocks ) )
1787 {
1788 // Only decrypt/strip off the signature if there is only one OpenPGP
1789 // block in the message
1790 if( pgpBlocks.count() == 1 )
1791 {
1792 Kpgp::Block* block = pgpBlocks.first();
1793 if( ( block->type() == Kpgp::PgpMessageBlock ) ||
1794 ( block->type() == Kpgp::ClearsignedBlock ) )
1795 {
1796 if( block->type() == Kpgp::PgpMessageBlock )
1797 // try to decrypt this OpenPGP block
1798 block->decrypt();
1799 else
1800 // strip off the signature
1801 block->verify();
1802
1803 body = nonPgpBlocks.first()
1804 + block->text()
1805 + nonPgpBlocks.last();
1806 }
1807 }
1808 }
1809}
1810
1811//-----------------------------------------------------------------------------
1812void KMComposeWin::setTransport( const TQString & transport )
1813{
1814 kdDebug(5006) << "KMComposeWin::setTransport( \"" << transport << "\" )" << endl;
1815 // Don't change the transport combobox if transport is empty
1816 if ( transport.isEmpty() )
1817 return;
1818
1819 bool transportFound = false;
1820 for ( int i = 0; i < mTransport->count(); ++i ) {
1821 if ( mTransport->text(i) == transport ) {
1822 transportFound = true;
1823 mTransport->setCurrentItem(i);
1824 kdDebug(5006) << "transport found, it's no. " << i << " in the list" << endl;
1825 break;
1826 }
1827 }
1828 if ( !transportFound ) { // unknown transport
1829 kdDebug(5006) << "unknown transport \"" << transport << "\"" << endl;
1830 if ( transport.startsWith("smtp://") || transport.startsWith("smtps://") ||
1831 transport.startsWith("file://") ) {
1832 // set custom transport
1833 mTransport->setEditText( transport );
1834 }
1835 else {
1836 // neither known nor custom transport -> use default transport
1837 mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
1838 }
1839 }
1840}
1841
1842//-----------------------------------------------------------------------------
1843void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
1844 bool allowDecryption, bool isModified)
1845{
1846 //assert(newMsg!=0);
1847 if(!newMsg)
1848 {
1849 kdDebug(5006) << "KMComposeWin::setMsg() : newMsg == 0!" << endl;
1850 return;
1851 }
1852 mMsg = newMsg;
1853 KPIM::IdentityManager * im = kmkernel->identityManager();
1854
1855 mEdtFrom->setText(mMsg->from());
1856 mEdtReplyTo->setText(mMsg->replyTo());
1857 if ( mClassicalRecipients ) {
1858 mEdtTo->setText(mMsg->to());
1859 mEdtCc->setText(mMsg->cc());
1860 mEdtBcc->setText(mMsg->bcc());
1861 } else {
1862 mRecipientsEditor->setRecipientString( mMsg->to(), Recipient::To );
1863 mRecipientsEditor->setRecipientString( mMsg->cc(), Recipient::Cc );
1864 mRecipientsEditor->setRecipientString( mMsg->bcc(), Recipient::Bcc );
1865 mRecipientsEditor->setFocusBottom();
1866 }
1867 mEdtSubject->setText(mMsg->subject());
1868
1869 const bool stickyIdentity = mBtnIdentity->isChecked() && !mIgnoreStickyFields;
1870 const bool messageHasIdentity = !newMsg->headerField("X-KMail-Identity").isEmpty();
1871 if (!stickyIdentity && messageHasIdentity)
1872 mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
1873
1874 // don't overwrite the header values with identity specific values
1875 // unless the identity is sticky
1876 if ( !stickyIdentity ) {
1877 disconnect(mIdentity,TQ_SIGNAL(identityChanged(uint)),
1878 this, TQ_SLOT(slotIdentityChanged(uint)));
1879 }
1880 // load the mId into the gui, sticky or not, without emitting
1881 mIdentity->setCurrentIdentity( mId );
1882 const uint idToApply = mId;
1883 if ( !stickyIdentity ) {
1884 connect(mIdentity,TQ_SIGNAL(identityChanged(uint)),
1885 this, TQ_SLOT(slotIdentityChanged(uint)));
1886 } else {
1887 // load the message's state into the mId, without applying it to the gui
1888 // that's so we can detect that the id changed (because a sticky was set)
1889 // on apply()
1890 if ( messageHasIdentity )
1891 mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
1892 else
1893 mId = im->defaultIdentity().uoid();
1894 }
1895 // manually load the identity's value into the fields; either the one from the
1896 // messge, where appropriate, or the one from the sticky identity. What's in
1897 // mId might have changed meanwhile, thus the save value
1898 slotIdentityChanged( idToApply );
1899
1900 const KPIM::Identity & ident = im->identityForUoid( mIdentity->currentIdentity() );
1901
1902 // check for the presence of a DNT header, indicating that MDN's were
1903 // requested
1904 TQString mdnAddr = newMsg->headerField("Disposition-Notification-To");
1905 mRequestMDNAction->setChecked( ( !mdnAddr.isEmpty() &&
1906 im->thatIsMe( mdnAddr ) ) ||
1907 GlobalSettings::self()->requestMDN() );
1908
1909 // check for presence of a priority header, indicating urgent mail:
1910 mUrgentAction->setChecked( newMsg->isUrgent() );
1911
1912 if (!ident.isXFaceEnabled() || ident.xface().isEmpty())
1913 mMsg->removeHeaderField("X-Face");
1914 else
1915 {
1916 TQString xface = ident.xface();
1917 if (!xface.isEmpty())
1918 {
1919 int numNL = ( xface.length() - 1 ) / 70;
1920 for ( int i = numNL; i > 0; --i )
1921 xface.insert( i*70, "\n\t" );
1922 mMsg->setHeaderField("X-Face", xface);
1923 }
1924 }
1925
1926 // enable/disable encryption if the message was/wasn't encrypted
1927 switch ( mMsg->encryptionState() ) {
1928 case KMMsgFullyEncrypted: // fall through
1929 case KMMsgPartiallyEncrypted:
1930 mLastEncryptActionState = true;
1931 break;
1932 case KMMsgNotEncrypted:
1933 mLastEncryptActionState = false;
1934 break;
1935 default: // nothing
1936 break;
1937 }
1938
1939 // enable/disable signing if the message was/wasn't signed
1940 switch ( mMsg->signatureState() ) {
1941 case KMMsgFullySigned: // fall through
1942 case KMMsgPartiallySigned:
1943 mLastSignActionState = true;
1944 break;
1945 case KMMsgNotSigned:
1946 mLastSignActionState = false;
1947 break;
1948 default: // nothing
1949 break;
1950 }
1951
1952 // if these headers are present, the state of the message should be overruled
1953 if ( mMsg->headers().FindField( "X-KMail-SignatureActionEnabled" ) )
1954 mLastSignActionState = (mMsg->headerField( "X-KMail-SignatureActionEnabled" ) == "true");
1955 if ( mMsg->headers().FindField( "X-KMail-EncryptActionEnabled" ) )
1956 mLastEncryptActionState = (mMsg->headerField( "X-KMail-EncryptActionEnabled" ) == "true");
1957 if ( mMsg->headers().FindField( "X-KMail-CryptoMessageFormat" ) )
1958 mCryptoModuleAction->setCurrentItem( format2cb( static_cast<Kleo::CryptoMessageFormat>(
1959 mMsg->headerField( "X-KMail-CryptoMessageFormat" ).toInt() ) ) );
1960
1961 mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
1962 mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
1963
1964 if ( Kleo::CryptoBackendFactory::instance()->openpgp() || Kleo::CryptoBackendFactory::instance()->smime() ) {
1965 const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
1966 && !ident.pgpSigningKey().isEmpty();
1967 const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
1968 && !ident.smimeSigningKey().isEmpty();
1969
1970 setEncryption( mLastEncryptActionState );
1971 setSigning( ( canOpenPGPSign || canSMIMESign ) && mLastSignActionState );
1972 }
1973 slotUpdateSignatureAndEncrypionStateIndicators();
1974
1975 // "Attach my public key" is only possible if the user uses OpenPGP
1976 // support and he specified his key:
1977 mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
1978 !ident.pgpEncryptionKey().isEmpty() );
1979
1980 TQString transport = newMsg->headerField("X-KMail-Transport");
1981 const bool stickyTransport = mBtnTransport->isChecked() && !mIgnoreStickyFields;
1982 if (!stickyTransport && !transport.isEmpty()) {
1983 setTransport( transport );
1984 }
1985
1986 // 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
1987 // See Bug 1239
1988 if (transport.isEmpty() && !mMsg->originatingAccountName().isEmpty()) {
1989 TQString transportCandidate = mMsg->originatingAccountName();
1990 bool transportFound = false;
1991 for ( int i = 0; i < mTransport->count(); ++i ) {
1992 if ( mTransport->text(i) == transportCandidate ) {
1993 transportFound = true;
1994 setTransport(transportCandidate);
1995 break;
1996 }
1997 }
1998 }
1999
2000 if (!mBtnFcc->isChecked())
2001 {
2002 if (!mMsg->fcc().isEmpty())
2003 setFcc(mMsg->fcc());
2004 else
2005 setFcc(ident.fcc());
2006 }
2007
2008 const bool stickyDictionary = mBtnDictionary->isChecked() && !mIgnoreStickyFields;
2009 if ( !stickyDictionary ) {
2010 mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
2011 }
2012
2013 partNode * root = partNode::fromMessage( mMsg );
2014
2015 KMail::ObjectTreeParser otp; // all defaults are ok
2016 otp.parseObjectTree( root );
2017
2018 KMail::AttachmentCollector ac;
2019 ac.collectAttachmentsFrom( root );
2020
2021 for ( std::vector<partNode*>::const_iterator it = ac.attachments().begin() ; it != ac.attachments().end() ; ++it )
2022 addAttach( new KMMessagePart( (*it)->msgPart() ) );
2023
2024 mEditor->setText( otp.textualContent() );
2025 mCharset = otp.textualContentCharset();
2026 if ( partNode * n = root->findType( DwMime::kTypeText, DwMime::kSubtypeHtml ) )
2027 if ( partNode * p = n->parentNode() )
2028 if ( p->hasType( DwMime::kTypeMultipart ) &&
2029 p->hasSubType( DwMime::kSubtypeAlternative ) )
2030 if ( mMsg->headerField( "X-KMail-Markup" ) == "true" ) {
2031 toggleMarkup( true );
2032
2033 // get cte decoded body part
2034 mCharset = n->msgPart().charset();
2035 TQCString bodyDecoded = n->msgPart().bodyDecoded();
2036
2037 // respect html part charset
2038 const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
2039 if ( codec ) {
2040 mEditor->setText( codec->toUnicode( bodyDecoded ) );
2041 } else {
2042 mEditor->setText( TQString::fromLocal8Bit( bodyDecoded ) );
2043 }
2044 }
2045
2046 if ( mCharset.isEmpty() )
2047 mCharset = mMsg->charset();
2048 if ( mCharset.isEmpty() )
2049 mCharset = mDefCharset;
2050 setCharset( mCharset );
2051
2052 /* Handle the special case of non-mime mails */
2053 if ( mMsg->numBodyParts() == 0 && otp.textualContent().isEmpty() ) {
2054 mCharset=mMsg->charset();
2055 if ( mCharset.isEmpty() || mCharset == "default" )
2056 mCharset = mDefCharset;
2057
2058 TQCString bodyDecoded = mMsg->bodyDecoded();
2059
2060 if( allowDecryption )
2061 decryptOrStripOffCleartextSignature( bodyDecoded );
2062
2063 const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
2064 if (codec) {
2065 mEditor->setText(codec->toUnicode(bodyDecoded));
2066 } else
2067 mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
2068 }
2069#ifdef BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
2070 const int num = mMsg->numBodyParts();
2071 kdDebug(5006) << "KMComposeWin::setMsg() mMsg->numBodyParts="
2072 << mMsg->numBodyParts() << endl;
2073
2074 if ( num > 0 ) {
2075 KMMessagePart bodyPart;
2076 int firstAttachment = 0;
2077
2078 mMsg->bodyPart(1, &bodyPart);
2079 if ( bodyPart.typeStr().lower() == "text" &&
2080 bodyPart.subtypeStr().lower() == "html" ) {
2081 // check whether we are inside a mp/al body part
2082 partNode *root = partNode::fromMessage( mMsg );
2083 partNode *node = root->findType( DwMime::kTypeText,
2084 DwMime::kSubtypeHtml );
2085 if ( node && node->parentNode() &&
2086 node->parentNode()->hasType( DwMime::kTypeMultipart ) &&
2087 node->parentNode()->hasSubType( DwMime::kSubtypeAlternative ) ) {
2088 // we have a mp/al body part with a text and an html body
2089 kdDebug(5006) << "KMComposeWin::setMsg() : text/html found" << endl;
2090 firstAttachment = 2;
2091 if ( mMsg->headerField( "X-KMail-Markup" ) == "true" )
2092 toggleMarkup( true );
2093 }
2094 delete root; root = 0;
2095 }
2096 if ( firstAttachment == 0 ) {
2097 mMsg->bodyPart(0, &bodyPart);
2098 if ( bodyPart.typeStr().lower() == "text" ) {
2099 // we have a mp/mx body with a text body
2100 kdDebug(5006) << "KMComposeWin::setMsg() : text/* found" << endl;
2101 firstAttachment = 1;
2102 }
2103 }
2104
2105 if ( firstAttachment != 0 ) // there's text to show
2106 {
2107 mCharset = bodyPart.charset();
2108 if ( mCharset.isEmpty() || mCharset == "default" )
2109 mCharset = mDefCharset;
2110
2111 TQCString bodyDecoded = bodyPart.bodyDecoded();
2112
2113 if( allowDecryption )
2114 decryptOrStripOffCleartextSignature( bodyDecoded );
2115
2116 // As nobody seems to know the purpose of the following line and
2117 // as it breaks word wrapping of long lines if drafts with attachments
2118 // are opened for editting in the composer (cf. Bug#41102) I comment it
2119 // out. Ingo, 2002-04-21
2120 //verifyWordWrapLengthIsAdequate(bodyDecoded);
2121
2122 const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
2123 if (codec)
2124 mEditor->setText(codec->toUnicode(bodyDecoded));
2125 else
2126 mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
2127 //mEditor->insertLine("\n", -1); <-- why ?
2128 } else mEditor->setText("");
2129 for( int i = firstAttachment; i < num; ++i )
2130 {
2131 KMMessagePart *msgPart = new KMMessagePart;
2132 mMsg->bodyPart(i, msgPart);
2133 TQCString mimeType = msgPart->typeStr().lower() + '/'
2134 + msgPart->subtypeStr().lower();
2135 // don't add the detached signature as attachment when editting a
2136 // PGP/MIME signed message
2137 if( mimeType != "application/pgp-signature" ) {
2138 addAttach(msgPart);
2139 }
2140 }
2141 } else{
2142 mCharset=mMsg->charset();
2143 if ( mCharset.isEmpty() || mCharset == "default" )
2144 mCharset = mDefCharset;
2145
2146 TQCString bodyDecoded = mMsg->bodyDecoded();
2147
2148 if( allowDecryption )
2149 decryptOrStripOffCleartextSignature( bodyDecoded );
2150
2151 const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
2152 if (codec) {
2153 mEditor->setText(codec->toUnicode(bodyDecoded));
2154 } else
2155 mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
2156 }
2157
2158 setCharset(mCharset);
2159#endif // BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
2160
2161 if( (GlobalSettings::self()->autoTextSignature()=="auto") && mayAutoSign ) {
2162 //
2163 // Espen 2000-05-16
2164 // Delay the signature appending. It may start a fileseletor.
2165 // Not user friendy if this modal fileseletor opens before the
2166 // composer.
2167 //
2168 //TQTimer::singleShot( 200, this, TQ_SLOT(slotAppendSignature()) );
2169 if ( GlobalSettings::self()->prependSignature() ) {
2170 TQTimer::singleShot( 0, this, TQ_SLOT(slotPrependSignature()) );
2171 } else {
2172 TQTimer::singleShot( 0, this, TQ_SLOT(slotAppendSignature()) );
2173 }
2174 }
2175
2176 if ( mMsg->getCursorPos() > 0 ) {
2177 // The message has a cursor position explicitly set, so avoid
2178 // changing it when appending the signature.
2179 mPreserveUserCursorPosition = true;
2180 }
2181 setModified( isModified );
2182
2183 // do this even for new messages
2184 mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
2185
2186 // honor "keep reply in this folder" setting even when the identity is changed later on
2187 mPreventFccOverwrite = ( !newMsg->fcc().isEmpty() && ident.fcc() != newMsg->fcc() );
2188}
2189
2190
2191//-----------------------------------------------------------------------------
2192void KMComposeWin::setFcc( const TQString &idString )
2193{
2194 // check if the sent-mail folder still exists
2195 if ( ! idString.isEmpty() && kmkernel->findFolderById( idString ) ) {
2196 mFcc->setFolder( idString );
2197 } else {
2198 mFcc->setFolder( kmkernel->sentFolder() );
2199 }
2200}
2201
2202
2203//-----------------------------------------------------------------------------
2204bool KMComposeWin::isModified() const
2205{
2206 return ( mEditor->isModified() ||
2207 mEdtFrom->edited() ||
2208 ( mEdtReplyTo && mEdtReplyTo->edited() ) ||
2209 ( mEdtTo && mEdtTo->edited() ) ||
2210 ( mEdtCc && mEdtCc->edited() ) ||
2211 ( mEdtBcc && mEdtBcc->edited() ) ||
2212 ( mRecipientsEditor && mRecipientsEditor->isModified() ) ||
2213 mEdtSubject->edited() ||
2214 mAtmModified ||
2215 ( mTransport->lineEdit() && mTransport->lineEdit()->edited() ) );
2216}
2217
2218
2219//-----------------------------------------------------------------------------
2220void KMComposeWin::setModified( bool modified )
2221{
2222 mEditor->setModified( modified );
2223 if ( !modified ) {
2224 mEdtFrom->setEdited( false );
2225 if ( mEdtReplyTo ) mEdtReplyTo->setEdited( false );
2226 if ( mEdtTo ) mEdtTo->setEdited( false );
2227 if ( mEdtCc ) mEdtCc->setEdited( false );
2228 if ( mEdtBcc ) mEdtBcc->setEdited( false );
2229 if ( mRecipientsEditor ) mRecipientsEditor->clearModified();
2230 mEdtSubject->setEdited( false );
2231 mAtmModified = false ;
2232 if ( mTransport->lineEdit() )
2233 mTransport->lineEdit()->setEdited( false );
2234 }
2235}
2236
2237
2238//-----------------------------------------------------------------------------
2239bool KMComposeWin::queryClose ()
2240{
2241 if ( !mEditor->checkExternalEditorFinished() )
2242 return false;
2243 if ( kmkernel->shuttingDown() || tdeApp->sessionSaving() )
2244 return true;
2245 if ( mComposer && mComposer->isPerformingSignOperation() ) // since the non-gpg-agent gpg plugin gets a passphrase using TQDialog::exec()
2246 return false; // the user can try to close the window, which destroys mComposer mid-call.
2247
2248 if ( isModified() ) {
2249 bool istemplate = ( mFolder!=0 && mFolder->isTemplates() );
2250 const TQString savebut = ( istemplate ?
2251 i18n("Re&save as Template") :
2252 i18n("&Save as Draft") );
2253 const TQString savetext = ( istemplate ?
2254 i18n("Resave this message in the Templates folder. "
2255 "It can then be used at a later time.") :
2256 i18n("Save this message in the Drafts folder. "
2257 "It can then be edited and sent at a later time.") );
2258
2259 const int rc = KMessageBox::warningYesNoCancel( this,
2260 i18n("Do you want to save the message for later or discard it?"),
2261 i18n("Close Composer"),
2262 KGuiItem(savebut, "document-save", TQString(), savetext),
2263 KStdGuiItem::discard() );
2264 if ( rc == KMessageBox::Cancel )
2265 return false;
2266 else if ( rc == KMessageBox::Yes ) {
2267 // doSend will close the window. Just return false from this method
2268 if ( istemplate ) {
2269 slotSaveTemplate();
2270 } else {
2271 slotSaveDraft();
2272 }
2273 return false;
2274 }
2275 }
2276 cleanupAutoSave();
2277 return true;
2278}
2279
2280//-----------------------------------------------------------------------------
2281bool KMComposeWin::userForgotAttachment()
2282{
2283 bool checkForForgottenAttachments =
2284 mCheckForForgottenAttachments && GlobalSettings::self()->showForgottenAttachmentWarning();
2285
2286 if ( !checkForForgottenAttachments || ( mAtmList.count() > 0 ) )
2287 return false;
2288
2289
2290 TQStringList attachWordsList = GlobalSettings::self()->attachmentKeywords();
2291
2292 if ( attachWordsList.isEmpty() ) {
2293 // default value (FIXME: this is duplicated in configuredialog.cpp)
2294 attachWordsList << TQString::fromLatin1("attachment")
2295 << TQString::fromLatin1("attached");
2296 if ( TQString::fromLatin1("attachment") != i18n("attachment") )
2297 attachWordsList << i18n("attachment");
2298 if ( TQString::fromLatin1("attached") != i18n("attached") )
2299 attachWordsList << i18n("attached");
2300 }
2301
2302 TQRegExp rx ( TQString::fromLatin1("\\b") +
2303 attachWordsList.join("\\b|\\b") +
2304 TQString::fromLatin1("\\b") );
2305 rx.setCaseSensitive( false );
2306
2307 bool gotMatch = false;
2308
2309 // check whether the subject contains one of the attachment key words
2310 // unless the message is a reply or a forwarded message
2311 TQString subj = subject();
2312 gotMatch = ( KMMessage::stripOffPrefixes( subj ) == subj )
2313 && ( rx.search( subj ) >= 0 );
2314
2315 if ( !gotMatch ) {
2316 // check whether the non-quoted text contains one of the attachment key
2317 // words
2318 TQRegExp quotationRx ("^([ \\t]*([|>:}#]|[A-Za-z]+>))+");
2319 for ( int i = 0; i < mEditor->numLines(); ++i ) {
2320 TQString line = mEditor->textLine( i );
2321 gotMatch = ( quotationRx.search( line ) < 0 )
2322 && ( rx.search( line ) >= 0 );
2323 if ( gotMatch )
2324 break;
2325 }
2326 }
2327
2328 if ( !gotMatch )
2329 return false;
2330
2331 int rc = KMessageBox::warningYesNoCancel( this,
2332 i18n("The message you have composed seems to refer to an "
2333 "attached file but you have not attached anything.\n"
2334 "Do you want to attach a file to your message?"),
2335 i18n("File Attachment Reminder"),
2336 i18n("&Attach File..."),
2337 i18n("&Send as Is") );
2338 if ( rc == KMessageBox::Cancel )
2339 return true;
2340 if ( rc == KMessageBox::Yes ) {
2341 slotAttachFile();
2342 //preceed with editing
2343 return true;
2344 }
2345 return false;
2346}
2347
2348//-----------------------------------------------------------------------------
2349void KMComposeWin::applyChanges( bool dontSignNorEncrypt, bool dontDisable )
2350{
2351 kdDebug(5006) << "entering KMComposeWin::applyChanges" << endl;
2352
2353 if(!mMsg || mComposer) {
2354 kdDebug(5006) << "KMComposeWin::applyChanges() : mMsg == 0!\n" << endl;
2355 emit applyChangesDone( false );
2356 return;
2357 }
2358
2359 // Make new job and execute it
2360 mComposer = new MessageComposer( this );
2361 connect( mComposer, TQ_SIGNAL( done( bool ) ),
2362 this, TQ_SLOT( slotComposerDone( bool ) ) );
2363
2364 // TODO: Add a cancel button for the following operations?
2365 // Disable any input to the window, so that we have a snapshot of the
2366 // composed stuff
2367 if ( !dontDisable ) setEnabled( false );
2368 // apply the current state to the composer and let it do it's thing
2369 mComposer->setDisableBreaking( mDisableBreaking ); // FIXME
2370 mComposer->applyChanges( dontSignNorEncrypt );
2371}
2372
2373void KMComposeWin::slotComposerDone( bool rc )
2374{
2375 deleteAll( mComposedMessages );
2376 mComposedMessages = mComposer->composedMessageList();
2377 emit applyChangesDone( rc );
2378 delete mComposer;
2379 mComposer = 0;
2380
2381 // re-enable the composewin, the messsage composition is now done
2382 setEnabled( true );
2383}
2384
2385const KPIM::Identity & KMComposeWin::identity() const {
2386 return kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
2387}
2388
2389uint KMComposeWin::identityUid() const {
2390 return mIdentity->currentIdentity();
2391}
2392
2393Kleo::CryptoMessageFormat KMComposeWin::cryptoMessageFormat() const {
2394 if ( !mCryptoModuleAction )
2395 return Kleo::AutoFormat;
2396 return cb2format( mCryptoModuleAction->currentItem() );
2397}
2398
2399bool KMComposeWin::encryptToSelf() const {
2400// return !Kpgp::Module::getKpgp() || Kpgp::Module::getKpgp()->encryptToSelf();
2401 TDEConfigGroup group( KMKernel::config(), "Composer" );
2402 return group.readBoolEntry( "crypto-encrypt-to-self", true );
2403}
2404
2405bool KMComposeWin::queryExit ()
2406{
2407 return true;
2408}
2409
2410//-----------------------------------------------------------------------------
2411bool KMComposeWin::addAttach(const KURL aUrl)
2412{
2413 if ( !aUrl.isValid() ) {
2414 KMessageBox::sorry( this, i18n( "<qt><p>KMail could not recognize the location of the attachment (%1);</p>"
2415 "<p>you have to specify the full path if you wish to attach a file.</p></qt>" )
2416 .arg( aUrl.prettyURL() ) );
2417 return false;
2418 }
2419
2420 const int maxAttachmentSize = GlobalSettings::maximumAttachmentSize();
2421 const uint maximumAttachmentSizeInByte = maxAttachmentSize*1024*1024;
2422 if ( aUrl.isLocalFile() && TQFileInfo( aUrl.pathOrURL() ).size() > maximumAttachmentSizeInByte ) {
2423 KMessageBox::sorry( this, i18n( "<qt><p>Your administrator has disallowed attaching files bigger than %1 MB.</p>" ).arg( maxAttachmentSize ) );
2424 return false;
2425 }
2426
2427 TDEIO::TransferJob *job = TDEIO::get(aUrl);
2428 TDEIO::Scheduler::scheduleJob( job );
2429 atmLoadData ld;
2430 ld.url = aUrl;
2431 ld.data = TQByteArray();
2432 ld.insert = false;
2433 if( !aUrl.fileEncoding().isEmpty() )
2434 ld.encoding = aUrl.fileEncoding().latin1();
2435
2436 mMapAtmLoadData.insert(job, ld);
2437 mAttachJobs[job] = aUrl;
2438 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
2439 this, TQ_SLOT(slotAttachFileResult(TDEIO::Job *)));
2440 connect(job, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
2441 this, TQ_SLOT(slotAttachFileData(TDEIO::Job *, const TQByteArray &)));
2442 return true;
2443}
2444
2445
2446//-----------------------------------------------------------------------------
2447void KMComposeWin::addAttach(const KMMessagePart* msgPart)
2448{
2449 mAtmList.append(msgPart);
2450
2451 // show the attachment listbox if it does not up to now
2452 if (mAtmList.count()==1)
2453 {
2454 mAtmListView->resize(mAtmListView->width(), 50);
2455 mAtmListView->show();
2456 resize(size());
2457 }
2458
2459 // add a line in the attachment listbox
2460 KMAtmListViewItem *lvi = new KMAtmListViewItem( mAtmListView );
2461 msgPartToItem(msgPart, lvi);
2462 mAtmItemList.append(lvi);
2463
2464 // the Attach file job has finished, so the possibly present tmp dir can be deleted now.
2465 if ( mTempDir != 0 ) {
2466 delete mTempDir;
2467 mTempDir = 0;
2468 }
2469
2470 connect( lvi, TQ_SIGNAL( compress( int ) ),
2471 this, TQ_SLOT( compressAttach( int ) ) );
2472 connect( lvi, TQ_SIGNAL( uncompress( int ) ),
2473 this, TQ_SLOT( uncompressAttach( int ) ) );
2474
2475 slotUpdateAttachActions();
2476}
2477
2478
2479//-----------------------------------------------------------------------------
2480void KMComposeWin::slotUpdateAttachActions()
2481{
2482 int selectedCount = 0;
2483 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it ) {
2484 if ( (*it)->isSelected() ) {
2485 ++selectedCount;
2486 }
2487 }
2488
2489 mAttachRemoveAction->setEnabled( selectedCount >= 1 );
2490 mAttachSaveAction->setEnabled( selectedCount == 1 );
2491 mAttachPropertiesAction->setEnabled( selectedCount == 1 );
2492}
2493
2494
2495//-----------------------------------------------------------------------------
2496
2497TQString KMComposeWin::prettyMimeType( const TQString& type )
2498{
2499 TQString t = type.lower();
2500 KServiceType::Ptr st = KServiceType::serviceType( t );
2501 return st ? st->comment() : t;
2502}
2503
2504void KMComposeWin::msgPartToItem(const KMMessagePart* msgPart,
2505 KMAtmListViewItem *lvi, bool loadDefaults)
2506{
2507 assert(msgPart != 0);
2508
2509 if (!msgPart->fileName().isEmpty())
2510 lvi->setText(0, msgPart->fileName());
2511 else
2512 lvi->setText(0, msgPart->name());
2513 lvi->setText(1, TDEIO::convertSize( msgPart->decodedSize()));
2514 lvi->setText(2, msgPart->contentTransferEncodingStr());
2515 lvi->setText(3, prettyMimeType(msgPart->typeStr() + "/" + msgPart->subtypeStr()));
2516 lvi->setAttachmentSize(msgPart->decodedSize());
2517
2518 if ( loadDefaults ) {
2519 if( canSignEncryptAttachments() ) {
2520 lvi->enableCryptoCBs( true );
2521 lvi->setEncrypt( mEncryptAction->isChecked() );
2522 lvi->setSign( mSignAction->isChecked() );
2523 } else {
2524 lvi->enableCryptoCBs( false );
2525 }
2526 }
2527}
2528
2529
2530//-----------------------------------------------------------------------------
2531void KMComposeWin::removeAttach(const TQString &aUrl)
2532{
2533 int idx;
2534 KMMessagePart* msgPart;
2535 for(idx=0,msgPart=mAtmList.first(); msgPart;
2536 msgPart=mAtmList.next(),idx++) {
2537 if (msgPart->name() == aUrl) {
2538 removeAttach(idx);
2539 return;
2540 }
2541 }
2542}
2543
2544
2545//-----------------------------------------------------------------------------
2546void KMComposeWin::removeAttach(int idx)
2547{
2548 mAtmModified = true;
2549
2550 KMAtmListViewItem *item = static_cast<KMAtmListViewItem*>( mAtmItemList.at( idx ) );
2551 if ( item->itemBelow() )
2552 mAtmSelectNew = item->itemBelow();
2553 else if ( item->itemAbove() )
2554 mAtmSelectNew = item->itemAbove();
2555
2556 mAtmList.remove(idx);
2557 delete mAtmItemList.take(idx);
2558
2559 if( mAtmList.isEmpty() )
2560 {
2561 mAtmListView->hide();
2562 mAtmListView->setMinimumSize(0, 0);
2563 resize(size());
2564 }
2565}
2566
2567
2568//-----------------------------------------------------------------------------
2569bool KMComposeWin::encryptFlagOfAttachment(int idx)
2570{
2571 return (int)(mAtmItemList.count()) > idx
2572 ? static_cast<KMAtmListViewItem*>( mAtmItemList.at( idx ) )->isEncrypt()
2573 : false;
2574}
2575
2576
2577//-----------------------------------------------------------------------------
2578bool KMComposeWin::signFlagOfAttachment(int idx)
2579{
2580 return (int)(mAtmItemList.count()) > idx
2581 ? ((KMAtmListViewItem*)(mAtmItemList.at( idx )))->isSign()
2582 : false;
2583}
2584
2585
2586//-----------------------------------------------------------------------------
2587void KMComposeWin::addrBookSelInto()
2588{
2589 if ( mClassicalRecipients ) {
2590 if ( GlobalSettings::self()->addresseeSelectorType() ==
2591 GlobalSettings::EnumAddresseeSelectorType::New ) {
2592 addrBookSelIntoNew();
2593 } else {
2594 addrBookSelIntoOld();
2595 }
2596 } else {
2597 kdWarning() << "To be implemented: call recipients picker." << endl;
2598 }
2599}
2600
2601void KMComposeWin::addrBookSelIntoOld()
2602{
2603 AddressesDialog dlg( this );
2604 TQString txt;
2605 TQStringList lst;
2606
2607 txt = to();
2608 if ( !txt.isEmpty() ) {
2609 lst = KPIM::splitEmailAddrList( txt );
2610 dlg.setSelectedTo( lst );
2611 }
2612
2613 txt = mEdtCc->text();
2614 if ( !txt.isEmpty() ) {
2615 lst = KPIM::splitEmailAddrList( txt );
2616 dlg.setSelectedCC( lst );
2617 }
2618
2619 txt = mEdtBcc->text();
2620 if ( !txt.isEmpty() ) {
2621 lst = KPIM::splitEmailAddrList( txt );
2622 dlg.setSelectedBCC( lst );
2623 }
2624
2625 dlg.setRecentAddresses( RecentAddresses::self( KMKernel::config() )->tdeabcAddresses() );
2626
2627 if (dlg.exec()==TQDialog::Rejected) return;
2628
2629 mEdtTo->setText( dlg.to().join(", ") );
2630 mEdtTo->setEdited( true );
2631
2632 mEdtCc->setText( dlg.cc().join(", ") );
2633 mEdtCc->setEdited( true );
2634
2635 mEdtBcc->setText( dlg.bcc().join(", ") );
2636 mEdtBcc->setEdited( true );
2637
2638 //Make sure BCC field is shown if needed
2639 if ( !mEdtBcc->text().isEmpty() ) {
2640 mShowHeaders |= HDR_BCC;
2641 rethinkFields( false );
2642 }
2643}
2644
2645void KMComposeWin::addrBookSelIntoNew()
2646{
2647 AddresseeEmailSelection selection;
2648
2649 AddresseeSelectorDialog dlg( &selection );
2650
2651 TQString txt;
2652 TQStringList lst;
2653
2654 txt = to();
2655 if ( !txt.isEmpty() ) {
2656 lst = KPIM::splitEmailAddrList( txt );
2657 selection.setSelectedTo( lst );
2658 }
2659
2660 txt = mEdtCc->text();
2661 if ( !txt.isEmpty() ) {
2662 lst = KPIM::splitEmailAddrList( txt );
2663 selection.setSelectedCC( lst );
2664 }
2665
2666 txt = mEdtBcc->text();
2667 if ( !txt.isEmpty() ) {
2668 lst = KPIM::splitEmailAddrList( txt );
2669 selection.setSelectedBCC( lst );
2670 }
2671
2672 if (dlg.exec()==TQDialog::Rejected) return;
2673
2674 TQStringList list = selection.to() + selection.toDistributionLists();
2675 mEdtTo->setText( list.join(", ") );
2676 mEdtTo->setEdited( true );
2677
2678 list = selection.cc() + selection.ccDistributionLists();
2679 mEdtCc->setText( list.join(", ") );
2680 mEdtCc->setEdited( true );
2681
2682 list = selection.bcc() + selection.bccDistributionLists();
2683 mEdtBcc->setText( list.join(", ") );
2684 mEdtBcc->setEdited( true );
2685
2686 //Make sure BCC field is shown if needed
2687 if ( !mEdtBcc->text().isEmpty() ) {
2688 mShowHeaders |= HDR_BCC;
2689 rethinkFields( false );
2690 }
2691}
2692
2693
2694//-----------------------------------------------------------------------------
2695void KMComposeWin::setCharset(const TQCString& aCharset, bool forceDefault)
2696{
2697 if ((forceDefault && GlobalSettings::self()->forceReplyCharset()) || aCharset.isEmpty())
2698 mCharset = mDefCharset;
2699 else
2700 mCharset = aCharset.lower();
2701
2702 if ( mCharset.isEmpty() || mCharset == "default" )
2703 mCharset = mDefCharset;
2704
2705 if (mAutoCharset)
2706 {
2707 mEncodingAction->setCurrentItem( 0 );
2708 return;
2709 }
2710
2711 TQStringList encodings = mEncodingAction->items();
2712 int i = 0;
2713 bool charsetFound = false;
2714 for ( TQStringList::Iterator it = encodings.begin(); it != encodings.end();
2715 ++it, i++ )
2716 {
2717 if (i > 0 && ((mCharset == "us-ascii" && i == 1) ||
2718 (i != 1 && TDEGlobal::charsets()->codecForName(
2719 TDEGlobal::charsets()->encodingForName(*it))
2720 == TDEGlobal::charsets()->codecForName(mCharset))))
2721 {
2722 mEncodingAction->setCurrentItem( i );
2723 slotSetCharset();
2724 charsetFound = true;
2725 break;
2726 }
2727 }
2728 if (!aCharset.isEmpty() && !charsetFound) setCharset("", true);
2729}
2730
2731
2732//-----------------------------------------------------------------------------
2733void KMComposeWin::slotAddrBook()
2734{
2735 KAddrBookExternal::openAddressBook(this);
2736}
2737
2738
2739//-----------------------------------------------------------------------------
2740void KMComposeWin::slotAddrBookFrom()
2741{
2742 addrBookSelInto();
2743}
2744
2745
2746//-----------------------------------------------------------------------------
2747void KMComposeWin::slotAddrBookReplyTo()
2748{
2749 addrBookSelInto();
2750}
2751
2752
2753//-----------------------------------------------------------------------------
2754void KMComposeWin::slotAddrBookTo()
2755{
2756 addrBookSelInto();
2757}
2758
2759//-----------------------------------------------------------------------------
2760void KMComposeWin::slotAttachFile()
2761{
2762 // Create File Dialog and return selected file(s)
2763 // We will not care about any permissions, existence or whatsoever in
2764 // this function.
2765
2766 // Handle the case where the last savedir is gone. kolab/issue4057
2767 TQString recent;
2768 KURL recentURL = KFileDialog::getStartURL( TQString(), recent );
2769 if ( !recentURL.url().isEmpty() &&
2770 !TDEIO::NetAccess::exists( recentURL, true, this ) ) {
2771 recentURL = KURL( TQDir::homeDirPath() );
2772 }
2773
2774 KFileDialog fdlg( recentURL.url(), TQString(), this, 0, true );
2775 fdlg.setOperationMode( KFileDialog::Other );
2776 fdlg.setCaption( i18n( "Attach File" ) );
2777 fdlg.okButton()->setGuiItem( KGuiItem( i18n( "&Attach" ),"document-open" ) );
2778 fdlg.setMode( KFile::Files );
2779 fdlg.exec();
2780 KURL::List files = fdlg.selectedURLs();
2781
2782 for (KURL::List::Iterator it = files.begin(); it != files.end(); ++it)
2783 addAttach(*it);
2784}
2785
2786
2787//-----------------------------------------------------------------------------
2788void KMComposeWin::slotAttachFileData(TDEIO::Job *job, const TQByteArray &data)
2789{
2790 TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
2791 assert(it != mMapAtmLoadData.end());
2792 TQBuffer buff((*it).data);
2793 buff.open(IO_WriteOnly | IO_Append);
2794 buff.writeBlock(data.data(), data.size());
2795 buff.close();
2796}
2797
2798
2799//-----------------------------------------------------------------------------
2800void KMComposeWin::slotAttachFileResult(TDEIO::Job *job)
2801{
2802 TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
2803 assert(it != mMapAtmLoadData.end());
2804 KURL attachURL;
2805 TQMap<TDEIO::Job*, KURL>::iterator jit = mAttachJobs.find(job);
2806 bool attachURLfound = (jit != mAttachJobs.end());
2807 if (attachURLfound)
2808 {
2809 attachURL = jit.data();
2810 mAttachJobs.remove(jit);
2811 }
2812 if (job->error())
2813 {
2814 mMapAtmLoadData.remove(it);
2815 job->showErrorDialog();
2816 if (attachURLfound)
2817 emit attachmentAdded(attachURL, false);
2818 return;
2819 }
2820 if ((*it).insert)
2821 {
2822 (*it).data.resize((*it).data.size() + 1);
2823 (*it).data[(*it).data.size() - 1] = '\0';
2824 if ( const TQTextCodec * codec = TDEGlobal::charsets()->codecForName((*it).encoding) )
2825 mEditor->insert( codec->toUnicode( (*it).data ) );
2826 else
2827 mEditor->insert( TQString::fromLocal8Bit( (*it).data ) );
2828 mMapAtmLoadData.remove(it);
2829 if (attachURLfound)
2830 emit attachmentAdded(attachURL, true);
2831 return;
2832 }
2833 TQCString partCharset;
2834 if ( !( *it ).url.fileEncoding().isEmpty() ) {
2835 partCharset = TQCString( ( *it ).url.fileEncoding().latin1() );
2836 } else {
2838 TDELocale *loc = TDEGlobal::locale();
2839 ed.setAutoDetectLanguage( EncodingDetector::scriptForLanguageCode ( loc->language() ) );
2840 ed.analyze( (*it).data );
2841 partCharset = ed.encoding();
2842 if ( partCharset.isEmpty() ) //shouldn't happen
2843 partCharset = mCharset;
2844 }
2845
2846 KMMessagePart* msgPart;
2847
2848 KCursorSaver busy(KBusyPtr::busy());
2849 TQString name( (*it).url.fileName() );
2850 // ask the job for the mime type of the file
2851 TQString mimeType = static_cast<TDEIO::MimetypeJob*>(job)->mimetype();
2852
2853 if ( name.isEmpty() ) {
2854 // URL ends with '/' (e.g. http://www.kde.org/)
2855 // guess a reasonable filename
2856 if( mimeType == "text/html" )
2857 name = "index.html";
2858 else {
2859 // try to determine a reasonable extension
2860 TQStringList patterns( KMimeType::mimeType( mimeType )->patterns() );
2861 TQString ext;
2862 if( !patterns.isEmpty() ) {
2863 ext = patterns[0];
2864 int i = ext.findRev( '.' );
2865 if( i == -1 )
2866 ext.prepend( '.' );
2867 else if( i > 0 )
2868 ext = ext.mid( i );
2869 }
2870 name = TQString("unknown") += ext;
2871 }
2872 }
2873
2874 name.truncate( 256 ); // is this needed?
2875
2876 TQCString encoding = KMMsgBase::autoDetectCharset(partCharset,
2878 if ( encoding.isEmpty() )
2879 encoding = "utf-8";
2880
2881 TQCString encName;
2882 if ( GlobalSettings::self()->outlookCompatibleAttachments() )
2883 encName = KMMsgBase::encodeRFC2047String( name, encoding );
2884 else
2885 encName = KMMsgBase::encodeRFC2231String( name, encoding );
2886 bool RFC2231encoded = false;
2887 if ( !GlobalSettings::self()->outlookCompatibleAttachments() )
2888 RFC2231encoded = name != TQString( encName );
2889
2890 // create message part
2891 msgPart = new KMMessagePart;
2892 msgPart->setName(name);
2893 TQValueList<int> allowedCTEs;
2894 if ( mimeType == "message/rfc822" ) {
2895 msgPart->setMessageBody( (*it).data );
2896 allowedCTEs << DwMime::kCte7bit;
2897 allowedCTEs << DwMime::kCte8bit;
2898 } else {
2899 msgPart->setBodyAndGuessCte((*it).data, allowedCTEs,
2900 !kmkernel->msgSender()->sendQuotedPrintable());
2901 kdDebug(5006) << "autodetected cte: " << msgPart->cteStr() << endl;
2902 }
2903 int slash = mimeType.find( '/' );
2904 if( slash == -1 )
2905 slash = mimeType.length();
2906 msgPart->setTypeStr( mimeType.left( slash ).latin1() );
2907 msgPart->setSubtypeStr( mimeType.mid( slash + 1 ).latin1() );
2908 msgPart->setContentDisposition(TQCString("attachment;\n\tfilename")
2909 + ( RFC2231encoded ? "*=" + encName : "=\"" + encName + '"' ) );
2910
2911 mMapAtmLoadData.remove(it);
2912
2913 if ( msgPart->typeStr().lower() == "text" ) {
2914 msgPart->setCharset(partCharset);
2915 }
2916
2917 // show message part dialog, if not configured away (default):
2918 TDEConfigGroup composer(KMKernel::config(), "Composer");
2919 if ( GlobalSettings::self()->showMessagePartDialogOnAttach() ) {
2920 const KCursorSaver saver( TQCursor::ArrowCursor );
2921 KMMsgPartDialogCompat dlg(mMainWidget);
2922 int encodings = 0;
2923 for ( TQValueListConstIterator<int> it = allowedCTEs.begin() ;
2924 it != allowedCTEs.end() ; ++it )
2925 switch ( *it ) {
2926 case DwMime::kCteBase64: encodings |= KMMsgPartDialog::Base64; break;
2927 case DwMime::kCteQp: encodings |= KMMsgPartDialog::QuotedPrintable; break;
2928 case DwMime::kCte7bit: encodings |= KMMsgPartDialog::SevenBit; break;
2929 case DwMime::kCte8bit: encodings |= KMMsgPartDialog::EightBit; break;
2930 default: ;
2931 }
2932 dlg.setShownEncodings( encodings );
2933 dlg.setMsgPart(msgPart);
2934 if (!dlg.exec()) {
2935 delete msgPart;
2936 msgPart = 0;
2937 if (attachURLfound)
2938 emit attachmentAdded(attachURL, false);
2939 return;
2940 }
2941 }
2942 mAtmModified = true;
2943
2944 // add the new attachment to the list
2945 addAttach(msgPart);
2946
2947 if (attachURLfound)
2948 emit attachmentAdded(attachURL, true);
2949}
2950
2951
2952//-----------------------------------------------------------------------------
2953void KMComposeWin::slotInsertFile()
2954{
2955 KFileDialog fdlg(TQString(), TQString(), this, 0, true);
2956 fdlg.setOperationMode( KFileDialog::Opening );
2957 fdlg.okButton()->setText(i18n("&Insert"));
2958 fdlg.setCaption(i18n("Insert File"));
2959 fdlg.toolBar()->insertCombo(KMMsgBase::supportedEncodings(false), 4711,
2960 false, 0, 0, 0);
2961 KComboBox *combo = fdlg.toolBar()->getCombo(4711);
2962 for (int i = 0; i < combo->count(); i++)
2963 if (TDEGlobal::charsets()->codecForName(TDEGlobal::charsets()->
2964 encodingForName(combo->text(i)))
2965 == TQTextCodec::codecForLocale()) combo->setCurrentItem(i);
2966 if (!fdlg.exec()) return;
2967
2968 KURL u = fdlg.selectedURL();
2969 mRecentAction->addURL(u);
2970 // Prevent race condition updating list when multiple composers are open
2971 {
2972 TDEConfig *config = KMKernel::config();
2973 TDEConfigGroupSaver saver( config, "Composer" );
2974 TQString encoding = TDEGlobal::charsets()->encodingForName(combo->currentText()).latin1();
2975 TQStringList urls = config->readListEntry( "recent-urls" );
2976 TQStringList encodings = config->readListEntry( "recent-encodings" );
2977 // Prevent config file from growing without bound
2978 // Would be nicer to get this constant from TDERecentFilesAction
2979 uint mMaxRecentFiles = 30;
2980 while (urls.count() > mMaxRecentFiles)
2981 urls.erase( urls.fromLast() );
2982 while (encodings.count() > mMaxRecentFiles)
2983 encodings.erase( encodings.fromLast() );
2984 // sanity check
2985 if (urls.count() != encodings.count()) {
2986 urls.clear();
2987 encodings.clear();
2988 }
2989 urls.prepend( u.prettyURL() );
2990 encodings.prepend( encoding );
2991 config->writeEntry( "recent-urls", urls );
2992 config->writeEntry( "recent-encodings", encodings );
2993 mRecentAction->saveEntries( config );
2994 }
2995 slotInsertRecentFile(u);
2996}
2997
2998
2999//-----------------------------------------------------------------------------
3000void KMComposeWin::slotInsertRecentFile(const KURL& u)
3001{
3002 if (u.fileName().isEmpty()) return;
3003
3004 TDEIO::Job *job = TDEIO::get(u);
3005 atmLoadData ld;
3006 ld.url = u;
3007 ld.data = TQByteArray();
3008 ld.insert = true;
3009 // Get the encoding previously used when inserting this file
3010 {
3011 TDEConfig *config = KMKernel::config();
3012 TDEConfigGroupSaver saver( config, "Composer" );
3013 TQStringList urls = config->readListEntry( "recent-urls" );
3014 TQStringList encodings = config->readListEntry( "recent-encodings" );
3015 int index = urls.findIndex( u.prettyURL() );
3016 if (index != -1) {
3017 TQString encoding = encodings[ index ];
3018 ld.encoding = encoding.latin1();
3019 }
3020 }
3021 mMapAtmLoadData.insert(job, ld);
3022 connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
3023 this, TQ_SLOT(slotAttachFileResult(TDEIO::Job *)));
3024 connect(job, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
3025 this, TQ_SLOT(slotAttachFileData(TDEIO::Job *, const TQByteArray &)));
3026}
3027
3028
3029//-----------------------------------------------------------------------------
3030void KMComposeWin::slotSetCharset()
3031{
3032 if (mEncodingAction->currentItem() == 0)
3033 {
3034 mAutoCharset = true;
3035 return;
3036 }
3037 mAutoCharset = false;
3038
3039 mCharset = TDEGlobal::charsets()->encodingForName( mEncodingAction->
3040 currentText() ).latin1();
3041}
3042
3043
3044//-----------------------------------------------------------------------------
3045void KMComposeWin::slotSelectCryptoModule( bool init )
3046{
3047 if ( !init ) {
3048 setModified( true );
3049 }
3050 if( canSignEncryptAttachments() ) {
3051 // if the encrypt/sign columns are hidden then show them
3052 if( 0 == mAtmListView->columnWidth( mAtmColEncrypt ) ) {
3053 // set/unset signing/encryption for all attachments according to the
3054 // state of the global sign/encrypt action
3055 if( !mAtmList.isEmpty() ) {
3056 for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
3057 lvi;
3058 lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
3059 lvi->setSign( mSignAction->isChecked() );
3060 lvi->setEncrypt( mEncryptAction->isChecked() );
3061 }
3062 }
3063 int totalWidth = 0;
3064 // determine the total width of the columns
3065 for( int col=0; col < mAtmColEncrypt; col++ )
3066 totalWidth += mAtmListView->columnWidth( col );
3067 int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
3068 - mAtmSignColWidth;
3069 // reduce the width of all columns so that the encrypt and sign column
3070 // fit
3071 int usedWidth = 0;
3072 for( int col=0; col < mAtmColEncrypt-1; col++ ) {
3073 int newWidth = mAtmListView->columnWidth( col ) * reducedTotalWidth
3074 / totalWidth;
3075 mAtmListView->setColumnWidth( col, newWidth );
3076 usedWidth += newWidth;
3077 }
3078 // the last column before the encrypt column gets the remaining space
3079 // (because of rounding errors the width of this column isn't calculated
3080 // the same way as the width of the other columns)
3081 mAtmListView->setColumnWidth( mAtmColEncrypt-1,
3082 reducedTotalWidth - usedWidth );
3083 mAtmListView->setColumnWidth( mAtmColEncrypt, mAtmEncryptColWidth );
3084 mAtmListView->setColumnWidth( mAtmColSign, mAtmSignColWidth );
3085 for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
3086 lvi;
3087 lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
3088 lvi->enableCryptoCBs( true );
3089 }
3090 }
3091 } else {
3092 // if the encrypt/sign columns are visible then hide them
3093 if( 0 != mAtmListView->columnWidth( mAtmColEncrypt ) ) {
3094 mAtmEncryptColWidth = mAtmListView->columnWidth( mAtmColEncrypt );
3095 mAtmSignColWidth = mAtmListView->columnWidth( mAtmColSign );
3096 int totalWidth = 0;
3097 // determine the total width of the columns
3098 for( int col=0; col < mAtmListView->columns(); col++ )
3099 totalWidth += mAtmListView->columnWidth( col );
3100 int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
3101 - mAtmSignColWidth;
3102 // increase the width of all columns so that the visible columns take
3103 // up the whole space
3104 int usedWidth = 0;
3105 for( int col=0; col < mAtmColEncrypt-1; col++ ) {
3106 int newWidth = mAtmListView->columnWidth( col ) * totalWidth
3107 / reducedTotalWidth;
3108 mAtmListView->setColumnWidth( col, newWidth );
3109 usedWidth += newWidth;
3110 }
3111 // the last column before the encrypt column gets the remaining space
3112 // (because of rounding errors the width of this column isn't calculated
3113 // the same way as the width of the other columns)
3114 mAtmListView->setColumnWidth( mAtmColEncrypt-1, totalWidth - usedWidth );
3115 mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
3116 mAtmListView->setColumnWidth( mAtmColSign, 0 );
3117 for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
3118 lvi;
3119 lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
3120 lvi->enableCryptoCBs( false );
3121 }
3122 }
3123 }
3124}
3125
3126static void showExportError( TQWidget * w, const GpgME::Error & err ) {
3127 assert( err );
3128 const TQString msg = i18n("<qt><p>An error occurred while trying to export "
3129 "the key from the backend:</p>"
3130 "<p><b>%1</b></p></qt>")
3131 .arg( TQString::fromLocal8Bit( err.asString() ) );
3132 KMessageBox::error( w, msg, i18n("Key Export Failed") );
3133}
3134
3135
3136//-----------------------------------------------------------------------------
3137void KMComposeWin::slotInsertMyPublicKey()
3138{
3139 // get PGP user id for the chosen identity
3140 mFingerprint =
3141 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() ).pgpEncryptionKey();
3142 if ( !mFingerprint.isEmpty() )
3143 startPublicKeyExport();
3144}
3145
3146void KMComposeWin::startPublicKeyExport() {
3147 if ( mFingerprint.isEmpty() || !Kleo::CryptoBackendFactory::instance()->openpgp() )
3148 return;
3149 Kleo::ExportJob * job = Kleo::CryptoBackendFactory::instance()->openpgp()->publicKeyExportJob( true );
3150 assert( job );
3151
3152 connect( job, TQ_SIGNAL(result(const GpgME::Error&,const TQByteArray&)),
3153 this, TQ_SLOT(slotPublicKeyExportResult(const GpgME::Error&,const TQByteArray&)) );
3154
3155 const GpgME::Error err = job->start( mFingerprint );
3156 if ( err )
3157 showExportError( this, err );
3158 else
3159 (void)new Kleo::ProgressDialog( job, i18n("Exporting key..."), this );
3160}
3161
3162void KMComposeWin::slotPublicKeyExportResult( const GpgME::Error & err, const TQByteArray & keydata ) {
3163 if ( err ) {
3164 showExportError( this, err );
3165 return;
3166 }
3167
3168 // create message part
3169 KMMessagePart * msgPart = new KMMessagePart();
3170 msgPart->setName( i18n("OpenPGP key 0x%1").arg( mFingerprint ) );
3171 msgPart->setTypeStr("application");
3172 msgPart->setSubtypeStr("pgp-keys");
3173 TQValueList<int> dummy;
3174 msgPart->setBodyAndGuessCte(keydata, dummy, false);
3175 msgPart->setContentDisposition( "attachment;\n\tfilename=0x" + TQCString( mFingerprint.latin1() ) + ".asc" );
3176
3177 // add the new attachment to the list
3178 addAttach(msgPart);
3179 rethinkFields(); //work around initial-size bug in TQt-1.32
3180}
3181
3182//-----------------------------------------------------------------------------
3183void KMComposeWin::slotInsertPublicKey()
3184{
3185 Kleo::KeySelectionDialog dlg( i18n("Attach Public OpenPGP Key"),
3186 i18n("Select the public key which should "
3187 "be attached."),
3188 std::vector<GpgME::Key>(),
3189 Kleo::KeySelectionDialog::PublicKeys|Kleo::KeySelectionDialog::OpenPGPKeys,
3190 false /* no multi selection */,
3191 false /* no remember choice box */,
3192 this, "attach public key selection dialog" );
3193 if ( dlg.exec() != TQDialog::Accepted )
3194 return;
3195
3196 mFingerprint = dlg.fingerprint();
3197 startPublicKeyExport();
3198}
3199
3200
3201//-----------------------------------------------------------------------------
3202void KMComposeWin::slotAttachPopupMenu(TQListViewItem *, const TQPoint &, int)
3203{
3204 if (!mAttachMenu)
3205 {
3206 mAttachMenu = new TQPopupMenu(this);
3207
3208 mOpenId = mAttachMenu->insertItem(i18n("to open", "Open"), this,
3209 TQ_SLOT(slotAttachOpen()));
3210 mOpenWithId = mAttachMenu->insertItem(i18n("Open With..."), this,
3211 TQ_SLOT(slotAttachOpenWith()));
3212 mViewId = mAttachMenu->insertItem(i18n("to view", "View"), this,
3213 TQ_SLOT(slotAttachView()));
3214 mEditId = mAttachMenu->insertItem( i18n("Edit"), this, TQ_SLOT(slotAttachEdit()) );
3215 mEditWithId = mAttachMenu->insertItem( i18n("Edit With..."), this,
3216 TQ_SLOT(slotAttachEditWith()) );
3217 mRemoveId = mAttachMenu->insertItem(i18n("Remove"), this, TQ_SLOT(slotAttachRemove()));
3218 mSaveAsId = mAttachMenu->insertItem( SmallIconSet("document-save-as"), i18n("Save As..."), this,
3219 TQ_SLOT( slotAttachSave() ) );
3220 mPropertiesId = mAttachMenu->insertItem( i18n("Properties"), this,
3221 TQ_SLOT( slotAttachProperties() ) );
3222 mAttachMenu->insertSeparator();
3223 mAttachMenu->insertItem(i18n("Add Attachment..."), this, TQ_SLOT(slotAttachFile()));
3224 }
3225
3226 int selectedCount = 0;
3227 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it ) {
3228 if ( (*it)->isSelected() ) {
3229 ++selectedCount;
3230 }
3231 }
3232
3233 mAttachMenu->setItemEnabled( mOpenId, selectedCount > 0 );
3234 mAttachMenu->setItemEnabled( mOpenWithId, selectedCount > 0 );
3235 mAttachMenu->setItemEnabled( mViewId, selectedCount > 0 );
3236 mAttachMenu->setItemEnabled( mEditId, selectedCount == 1 );
3237 mAttachMenu->setItemEnabled( mEditWithId, selectedCount == 1 );
3238 mAttachMenu->setItemEnabled( mRemoveId, selectedCount > 0 );
3239 mAttachMenu->setItemEnabled( mSaveAsId, selectedCount == 1 );
3240 mAttachMenu->setItemEnabled( mPropertiesId, selectedCount == 1 );
3241
3242 mAttachMenu->popup(TQCursor::pos());
3243}
3244
3245//-----------------------------------------------------------------------------
3246int KMComposeWin::currentAttachmentNum()
3247{
3248 int i = 0;
3249 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i )
3250 if ( *it == mAtmListView->currentItem() )
3251 return i;
3252 return -1;
3253}
3254
3255//-----------------------------------------------------------------------------
3256void KMComposeWin::slotAttachProperties()
3257{
3258 int idx = currentAttachmentNum();
3259
3260 if (idx < 0) return;
3261
3262 KMMessagePart* msgPart = mAtmList.at(idx);
3263
3264 KMMsgPartDialogCompat dlg(mMainWidget);
3265 dlg.setMsgPart(msgPart);
3266 KMAtmListViewItem* listItem = (KMAtmListViewItem*)(mAtmItemList.at(idx));
3267 if( canSignEncryptAttachments() && listItem ) {
3268 dlg.setCanSign( true );
3269 dlg.setCanEncrypt( true );
3270 dlg.setSigned( listItem->isSign() );
3271 dlg.setEncrypted( listItem->isEncrypt() );
3272 } else {
3273 dlg.setCanSign( false );
3274 dlg.setCanEncrypt( false );
3275 }
3276 if (dlg.exec())
3277 {
3278 mAtmModified = true;
3279 // values may have changed, so recreate the listbox line
3280 if( listItem ) {
3281 msgPartToItem(msgPart, listItem);
3282 if( canSignEncryptAttachments() ) {
3283 listItem->setSign( dlg.isSigned() );
3284 listItem->setEncrypt( dlg.isEncrypted() );
3285 }
3286 }
3287 }
3288}
3289
3290//-----------------------------------------------------------------------------
3291void KMComposeWin::compressAttach( int idx )
3292{
3293 if (idx < 0) return;
3294
3295 unsigned int i;
3296 for ( i = 0; i < mAtmItemList.count(); ++i )
3297 if ( mAtmItemList.at( i )->itemPos() == idx )
3298 break;
3299
3300 if ( i > mAtmItemList.count() )
3301 return;
3302
3303 KMMessagePart* msgPart;
3304 msgPart = mAtmList.at( i );
3305 TQByteArray array;
3306 TQBuffer dev( array );
3307 KZip zip( &dev );
3308 TQByteArray decoded = msgPart->bodyDecodedBinary();
3309 if ( ! zip.open( IO_WriteOnly ) ) {
3310 KMessageBox::sorry(0, i18n("KMail could not compress the file.") );
3311 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
3312 return;
3313 }
3314
3315 zip.setCompression( KZip::DeflateCompression );
3316 if ( ! zip.writeFile( msgPart->name(), "", "", decoded.size(),
3317 decoded.data() ) ) {
3318 KMessageBox::sorry(0, i18n("KMail could not compress the file.") );
3319 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
3320 return;
3321 }
3322 zip.close();
3323 if ( array.size() >= decoded.size() ) {
3324 if ( KMessageBox::questionYesNo( this, i18n("The compressed file is larger "
3325 "than the original. Do you want to keep the original one?" ), TQString(), i18n("Keep"), i18n("Compress") )
3326 == KMessageBox::Yes ) {
3327 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
3328 return;
3329 }
3330 }
3331 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setUncompressedCodec(
3332 msgPart->cteStr() );
3333
3334 msgPart->setCteStr( "base64" );
3335 msgPart->setBodyEncodedBinary( array );
3336 TQString name = msgPart->name() + ".zip";
3337
3338 msgPart->setName( name );
3339
3340 TQCString cDisp = "attachment;";
3341 TQCString encoding = KMMsgBase::autoDetectCharset( msgPart->charset(),
3343 kdDebug(5006) << "encoding: " << encoding << endl;
3344 if ( encoding.isEmpty() ) encoding = "utf-8";
3345 kdDebug(5006) << "encoding after: " << encoding << endl;
3346 TQCString encName;
3347 if ( GlobalSettings::self()->outlookCompatibleAttachments() )
3348 encName = KMMsgBase::encodeRFC2047String( name, encoding );
3349 else
3350 encName = KMMsgBase::encodeRFC2231String( name, encoding );
3351
3352 cDisp += "\n\tfilename";
3353 if ( name != TQString( encName ) )
3354 cDisp += "*=" + encName;
3355 else
3356 cDisp += "=\"" + encName + '"';
3357 msgPart->setContentDisposition( cDisp );
3358
3359 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setUncompressedMimeType(
3360 msgPart->typeStr(), msgPart->subtypeStr() );
3361 msgPart->setTypeStr( "application" );
3362 msgPart->setSubtypeStr( "x-zip" );
3363
3364 KMAtmListViewItem* listItem = static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) );
3365 msgPartToItem( msgPart, listItem, false );
3366}
3367
3368//-----------------------------------------------------------------------------
3369
3370void KMComposeWin::uncompressAttach( int idx )
3371{
3372 if (idx < 0) return;
3373
3374 unsigned int i;
3375 for ( i = 0; i < mAtmItemList.count(); ++i )
3376 if ( mAtmItemList.at( i )->itemPos() == idx )
3377 break;
3378
3379 if ( i > mAtmItemList.count() )
3380 return;
3381
3382 KMMessagePart* msgPart;
3383 msgPart = mAtmList.at( i );
3384
3385 TQBuffer dev( msgPart->bodyDecodedBinary() );
3386 KZip zip( &dev );
3387 TQByteArray decoded;
3388
3389 decoded = msgPart->bodyDecodedBinary();
3390 if ( ! zip.open( IO_ReadOnly ) ) {
3391 KMessageBox::sorry(0, i18n("KMail could not uncompress the file.") );
3392 static_cast<KMAtmListViewItem *>( mAtmItemList.at( i ) )->setCompress( true );
3393 return;
3394 }
3395 const KArchiveDirectory *dir = zip.directory();
3396
3397 KZipFileEntry *entry;
3398 if ( dir->entries().count() != 1 ) {
3399 KMessageBox::sorry(0, i18n("KMail could not uncompress the file.") );
3400 static_cast<KMAtmListViewItem *>( mAtmItemList.at( i ) )->setCompress( true );
3401 return;
3402 }
3403 entry = (KZipFileEntry*)dir->entry( dir->entries()[0] );
3404
3405 msgPart->setCteStr(
3406 static_cast<KMAtmListViewItem*>( mAtmItemList.at(i) )->uncompressedCodec() );
3407
3408 msgPart->setBodyEncodedBinary( entry->data() );
3409 TQString name = entry->name();
3410 msgPart->setName( name );
3411
3412 zip.close();
3413
3414 TQCString cDisp = "attachment;";
3415 TQCString encoding = KMMsgBase::autoDetectCharset( msgPart->charset(),
3417 if ( encoding.isEmpty() ) encoding = "utf-8";
3418
3419 TQCString encName;
3420 if ( GlobalSettings::self()->outlookCompatibleAttachments() )
3421 encName = KMMsgBase::encodeRFC2047String( name, encoding );
3422 else
3423 encName = KMMsgBase::encodeRFC2231String( name, encoding );
3424
3425 cDisp += "\n\tfilename";
3426 if ( name != TQString( encName ) )
3427 cDisp += "*=" + encName;
3428 else
3429 cDisp += "=\"" + encName + '"';
3430 msgPart->setContentDisposition( cDisp );
3431
3432 TQCString type, subtype;
3433 static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->uncompressedMimeType( type,
3434 subtype );
3435
3436 msgPart->setTypeStr( type );
3437 msgPart->setSubtypeStr( subtype );
3438
3439 KMAtmListViewItem* listItem = static_cast<KMAtmListViewItem*>(mAtmItemList.at( i ));
3440 msgPartToItem( msgPart, listItem, false );
3441}
3442
3443
3444//-----------------------------------------------------------------------------
3445void KMComposeWin::slotAttachView()
3446{
3447 int i = 0;
3448 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
3449 if ( (*it)->isSelected() ) {
3450 viewAttach( i );
3451 }
3452 }
3453}
3454//-----------------------------------------------------------------------------
3455void KMComposeWin::slotAttachOpen()
3456{
3457 int i = 0;
3458 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
3459 if ( (*it)->isSelected() ) {
3460 openAttach( i, false );
3461 }
3462 }
3463}
3464
3465//-----------------------------------------------------------------------------
3466void KMComposeWin::slotAttachOpenWith()
3467{
3468 int i = 0;
3469 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
3470 if ( (*it)->isSelected() ) {
3471 openAttach( i, true );
3472 }
3473 }
3474}
3475
3476void KMComposeWin::slotAttachEdit()
3477{
3478 int i = 0;
3479 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
3480 if ( (*it)->isSelected() ) {
3481 editAttach( i, false );
3482 }
3483 }
3484}
3485
3486void KMComposeWin::slotAttachEditWith()
3487{
3488 int i = 0;
3489 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
3490 if ( (*it)->isSelected() ) {
3491 editAttach( i, true );
3492 }
3493 }
3494}
3495
3496//-----------------------------------------------------------------------------
3497bool KMComposeWin::inlineSigningEncryptionSelected() {
3498 if ( !mSignAction->isChecked() && !mEncryptAction->isChecked() )
3499 return false;
3500 return cryptoMessageFormat() == Kleo::InlineOpenPGPFormat;
3501}
3502
3503//-----------------------------------------------------------------------------
3504void KMComposeWin::viewAttach( int index )
3505{
3506 TQString pname;
3507 KMMessagePart* msgPart;
3508 msgPart = mAtmList.at(index);
3509 pname = msgPart->name().stripWhiteSpace();
3510 if (pname.isEmpty()) pname=msgPart->contentDescription();
3511 if (pname.isEmpty()) pname="unnamed";
3512
3513 KTempFile* atmTempFile = new KTempFile();
3514 mAtmTempList.append( atmTempFile );
3515 atmTempFile->setAutoDelete( true );
3516 KPIM::kByteArrayToFile(msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
3517 false);
3518 KMReaderMainWin *win = new KMReaderMainWin(msgPart, false,
3519 atmTempFile->name(), pname, mCharset );
3520 win->show();
3521}
3522
3523//-----------------------------------------------------------------------------
3524void KMComposeWin::openAttach( int index, bool with )
3525{
3526 KMMessagePart* msgPart = mAtmList.at(index);
3527 const TQString contentTypeStr =
3528 ( msgPart->typeStr() + '/' + msgPart->subtypeStr() ).lower();
3529
3530 KMimeType::Ptr mimetype;
3531 mimetype = KMimeType::mimeType( contentTypeStr );
3532
3533 KTempFile* atmTempFile = new KTempFile();
3534 mAtmTempList.append( atmTempFile );
3535 const bool autoDelete = true;
3536 atmTempFile->setAutoDelete( autoDelete );
3537
3538 KURL url;
3539 url.setPath( atmTempFile->name() );
3540
3541 KPIM::kByteArrayToFile( msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
3542 false );
3543 if ( ::chmod( TQFile::encodeName( atmTempFile->name() ), S_IRUSR ) != 0) {
3544 TQFile::remove(url.path());
3545 return;
3546 }
3547
3548 KService::Ptr offer =
3549 KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
3550
3551 if ( with || !offer || mimetype->name() == "application/octet-stream" ) {
3552 if ( ( !KRun::displayOpenWithDialog( url, autoDelete ) ) && autoDelete ) {
3553 TQFile::remove(url.path());
3554 }
3555 }
3556 else {
3557 if ( ( !KRun::run( *offer, url, autoDelete ) ) && autoDelete ) {
3558 TQFile::remove( url.path() );
3559 }
3560 }
3561}
3562
3563void KMComposeWin::editAttach(int index, bool openWith)
3564{
3565 KMMessagePart* msgPart = mAtmList.at(index);
3566 const TQString contentTypeStr =
3567 ( msgPart->typeStr() + '/' + msgPart->subtypeStr() ).lower();
3568
3569 KTempFile* atmTempFile = new KTempFile();
3570 mAtmTempList.append( atmTempFile );
3571 atmTempFile->setAutoDelete( true );
3572 atmTempFile->file()->writeBlock( msgPart->bodyDecodedBinary() );
3573 atmTempFile->file()->flush();
3574
3575
3576 KMail::EditorWatcher *watcher =
3577 new KMail::EditorWatcher( KURL( atmTempFile->name() ), contentTypeStr, openWith,
3578 this, this );
3579 connect( watcher, TQ_SIGNAL(editDone(KMail::EditorWatcher*)), TQ_SLOT(slotEditDone(KMail::EditorWatcher*)) );
3580 if ( watcher->start() ) {
3581 mEditorMap.insert( watcher, msgPart );
3582 mEditorTempFiles.insert( watcher, atmTempFile );
3583 }
3584}
3585
3586//-----------------------------------------------------------------------------
3587void KMComposeWin::slotAttachSave()
3588{
3589 KMMessagePart* msgPart;
3590 TQString fileName, pname;
3591 int idx = currentAttachmentNum();
3592
3593 if (idx < 0) return;
3594
3595 msgPart = mAtmList.at(idx);
3596 pname = msgPart->name();
3597 if (pname.isEmpty()) pname="unnamed";
3598
3599 KURL url = KFileDialog::getSaveURL(pname, TQString(), 0, i18n("Save Attachment As"));
3600
3601 if( url.isEmpty() )
3602 return;
3603
3604 kmkernel->byteArrayToRemoteFile(msgPart->bodyDecodedBinary(), url);
3605}
3606
3607
3608//-----------------------------------------------------------------------------
3609void KMComposeWin::slotAttachRemove()
3610{
3611 mAtmSelectNew = 0;
3612 bool attachmentRemoved = false;
3613 int i = 0;
3614 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ) {
3615 if ( (*it)->isSelected() ) {
3616 removeAttach( i );
3617 attachmentRemoved = true;
3618 }
3619 else {
3620 ++it;
3621 ++i;
3622 }
3623 }
3624
3625 if ( attachmentRemoved ) {
3626 setModified( true );
3627 slotUpdateAttachActions();
3628 if ( mAtmSelectNew ) {
3629 mAtmListView->setSelected( mAtmSelectNew, true );
3630 mAtmListView->setCurrentItem( mAtmSelectNew );
3631 }
3632 }
3633}
3634
3635//-----------------------------------------------------------------------------
3636void KMComposeWin::slotFind()
3637{
3638 mEditor->search();
3639}
3640
3641void KMComposeWin::slotSearchAgain()
3642{
3643 mEditor->repeatSearch();
3644}
3645
3646//-----------------------------------------------------------------------------
3647void KMComposeWin::slotReplace()
3648{
3649 mEditor->replace();
3650}
3651
3652//-----------------------------------------------------------------------------
3653void KMComposeWin::slotUpdateFont()
3654{
3655 kdDebug() << "KMComposeWin::slotUpdateFont " << endl;
3656 if ( ! mFixedFontAction ) {
3657 return;
3658 }
3659 mEditor->setFont( mFixedFontAction->isChecked() ? mFixedFont : mBodyFont );
3660}
3661
3662TQString KMComposeWin::quotePrefixName() const
3663{
3664 if ( !msg() )
3665 return TQString();
3666
3667 int languageNr = GlobalSettings::self()->replyCurrentLanguage();
3668 ReplyPhrases replyPhrases( TQString::number(languageNr) );
3669 replyPhrases.readConfig();
3670 TQString quotePrefix = msg()->formatString(
3671 replyPhrases.indentPrefix() );
3672
3673 quotePrefix = msg()->formatString(quotePrefix);
3674 return quotePrefix;
3675}
3676
3677void KMComposeWin::slotPasteClipboardAsQuotation()
3678{
3679 if( mEditor->hasFocus() && msg() )
3680 {
3681 TQString s = TQApplication::clipboard()->text();
3682 if (!s.isEmpty())
3683 mEditor->insert(addQuotesToText(s));
3684 }
3685}
3686
3687void KMComposeWin::slotPasteClipboardAsAttachment()
3688{
3689 KURL url( TQApplication::clipboard()->text( TQClipboard::Clipboard ) );
3690 if ( url.isValid() ) {
3691 addAttach(TQApplication::clipboard()->text( TQClipboard::Clipboard ) );
3692 return;
3693 }
3694
3695 TQMimeSource *mimeSource = TQApplication::clipboard()->data();
3696 if ( TQImageDrag::canDecode(mimeSource) ) {
3697 slotAttachPNGImageData(mimeSource->encodedData("image/png"));
3698 }
3699 else {
3700 bool ok;
3701 TQString attName = KInputDialog::getText( "KMail", i18n("Name of the attachment:"), TQString(), &ok, this );
3702 if ( !ok )
3703 return;
3704 KMMessagePart *msgPart = new KMMessagePart;
3705 msgPart->setName(attName);
3706 TQValueList<int> dummy;
3707 msgPart->setBodyAndGuessCte(TQCString(TQApplication::clipboard()->text().latin1()), dummy,
3708 kmkernel->msgSender()->sendQuotedPrintable());
3709 addAttach(msgPart);
3710 }
3711}
3712
3713void KMComposeWin::slotAddQuotes()
3714{
3715 if( mEditor->hasFocus() && msg() )
3716 {
3717 // TODO: I think this is backwards.
3718 // i.e, if no region is marked then add quotes to every line
3719 // else add quotes only on the lines that are marked.
3720
3721 if ( mEditor->hasMarkedText() ) {
3722 TQString s = mEditor->markedText();
3723 if(!s.isEmpty())
3724 mEditor->insert(addQuotesToText(s));
3725 } else {
3726 int l = mEditor->currentLine();
3727 int c = mEditor->currentColumn();
3728 TQString s = mEditor->textLine(l);
3729 s.prepend(quotePrefixName());
3730 mEditor->insertLine(s,l);
3731 mEditor->removeLine(l+1);
3732 mEditor->setCursorPosition(l,c+2);
3733 }
3734 }
3735}
3736
3737TQString KMComposeWin::addQuotesToText(const TQString &inputText)
3738{
3739 TQString answer = TQString( inputText );
3740 TQString indentStr = quotePrefixName();
3741 answer.replace( '\n', '\n' + indentStr);
3742 answer.prepend( indentStr );
3743 answer += '\n';
3744 return KMMessage::smartQuote( answer, GlobalSettings::self()->lineWrapWidth() );
3745}
3746
3747TQString KMComposeWin::removeQuotesFromText(const TQString &inputText)
3748{
3749 TQString s = inputText;
3750
3751 // remove first leading quote
3752 TQString quotePrefix = '^' + quotePrefixName();
3753 TQRegExp rx(quotePrefix);
3754 s.remove(rx);
3755
3756 // now remove all remaining leading quotes
3757 quotePrefix = '\n' + quotePrefixName();
3758 rx = quotePrefix;
3759 s.replace(rx, "\n");
3760
3761 return s;
3762}
3763
3764void KMComposeWin::slotRemoveQuotes()
3765{
3766 if( mEditor->hasFocus() && msg() )
3767 {
3768 // TODO: I think this is backwards.
3769 // i.e, if no region is marked then remove quotes from every line
3770 // else remove quotes only on the lines that are marked.
3771
3772 if ( mEditor->hasMarkedText() ) {
3773 TQString s = mEditor->markedText();
3774 mEditor->insert(removeQuotesFromText(s));
3775 } else {
3776 int l = mEditor->currentLine();
3777 int c = mEditor->currentColumn();
3778 TQString s = mEditor->textLine(l);
3779 mEditor->insertLine(removeQuotesFromText(s),l);
3780 mEditor->removeLine(l+1);
3781 mEditor->setCursorPosition(l,c-2);
3782 }
3783 }
3784}
3785
3786//-----------------------------------------------------------------------------
3787void KMComposeWin::slotUndo()
3788{
3789 TQWidget* fw = focusWidget();
3790 if (!fw) return;
3791
3792 if ( ::tqt_cast<KEdit*>(fw) )
3793 static_cast<TQTextEdit*>(fw)->undo();
3794 else if (::tqt_cast<TQLineEdit*>(fw))
3795 static_cast<TQLineEdit*>(fw)->undo();
3796}
3797
3798void KMComposeWin::slotRedo()
3799{
3800 TQWidget* fw = focusWidget();
3801 if (!fw) return;
3802
3803 if (::tqt_cast<KEdit*>(fw))
3804 static_cast<KEdit*>(fw)->redo();
3805 else if (::tqt_cast<TQLineEdit*>(fw))
3806 static_cast<TQLineEdit*>(fw)->redo();
3807}
3808
3809//-----------------------------------------------------------------------------
3810void KMComposeWin::slotCut()
3811{
3812 TQWidget* fw = focusWidget();
3813 if (!fw) return;
3814
3815 if (::tqt_cast<KEdit*>(fw))
3816 static_cast<KEdit*>(fw)->cut();
3817 else if (::tqt_cast<TQLineEdit*>(fw))
3818 static_cast<TQLineEdit*>(fw)->cut();
3819}
3820
3821
3822//-----------------------------------------------------------------------------
3823void KMComposeWin::slotCopy()
3824{
3825 TQWidget* fw = focusWidget();
3826 if (!fw) return;
3827
3828#ifdef KeyPress
3829#undef KeyPress
3830#endif
3831
3832 TQKeyEvent k(TQEvent::KeyPress, Key_C, 0, ControlButton);
3833 tdeApp->notify(fw, &k);
3834}
3835
3836
3837//-----------------------------------------------------------------------------
3838void KMComposeWin::slotPasteClipboard()
3839{
3840 paste( TQClipboard::Clipboard );
3841}
3842
3843void KMComposeWin::paste( TQClipboard::Mode mode )
3844{
3845 TQWidget* fw = focusWidget();
3846 if (!fw) return;
3847
3848 TQMimeSource *mimeSource = TQApplication::clipboard()->data( mode );
3849 if ( mimeSource->provides("image/png") ) {
3850 slotAttachPNGImageData(mimeSource->encodedData("image/png"));
3851 } else if ( KURLDrag::canDecode( mimeSource ) ) {
3852 KURL::List urlList;
3853 if( KURLDrag::decode( mimeSource, urlList ) ) {
3854 const TQString asText = i18n("Add as Text");
3855 const TQString asAttachment = i18n("Add as Attachment");
3856 const TQString text = i18n("Please select whether you want to insert the content as text into the editor, "
3857 "or append the referenced file as an attachment.");
3858 const TQString caption = i18n("Paste as text or attachment?");
3859
3860 int id = KMessageBox::questionYesNoCancel( this, text, caption,
3861 KGuiItem( asText ), KGuiItem( asAttachment) );
3862 switch ( id) {
3863 case KMessageBox::Yes:
3864 for ( KURL::List::Iterator it = urlList.begin();
3865 it != urlList.end(); ++it ) {
3866 mEditor->insert( (*it).url() );
3867 }
3868 break;
3869 case KMessageBox::No:
3870 for ( KURL::List::Iterator it = urlList.begin();
3871 it != urlList.end(); ++it ) {
3872 addAttach( *it );
3873 }
3874 break;
3875 }
3876 }
3877 } else if ( TQTextDrag::canDecode( mimeSource ) ) {
3878 TQString s;
3879 if ( TQTextDrag::decode( mimeSource, s ) )
3880 mEditor->insert( s );
3881 }
3882}
3883
3884
3885//-----------------------------------------------------------------------------
3886void KMComposeWin::slotMarkAll()
3887{
3888 TQWidget* fw = focusWidget();
3889 if (!fw) return;
3890
3891 if (::tqt_cast<TQLineEdit*>(fw))
3892 static_cast<TQLineEdit*>(fw)->selectAll();
3893 else if (::tqt_cast<KEdit*>(fw))
3894 static_cast<KEdit*>(fw)->selectAll();
3895}
3896
3897
3898//-----------------------------------------------------------------------------
3899void KMComposeWin::slotClose()
3900{
3901 close(false);
3902}
3903
3904
3905//-----------------------------------------------------------------------------
3906void KMComposeWin::slotNewComposer()
3907{
3908 KMComposeWin* win;
3909 KMMessage* msg = new KMMessage;
3910
3911 msg->initHeader();
3912 win = new KMComposeWin(msg);
3913 win->show();
3914}
3915
3916
3917//-----------------------------------------------------------------------------
3918void KMComposeWin::slotNewMailReader()
3919{
3920 KMMainWin *kmmwin = new KMMainWin(0);
3921 kmmwin->show();
3922 //d->resize(d->size());
3923}
3924
3925
3926//-----------------------------------------------------------------------------
3927void KMComposeWin::slotUpdWinTitle(const TQString& text)
3928{
3929 TQString s( text );
3930 // Remove characters that show badly in most window decorations:
3931 // newlines tend to become boxes.
3932 if (text.isEmpty())
3933 setCaption("("+i18n("unnamed")+")");
3934 else setCaption( s.replace( TQChar('\n'), ' ' ) );
3935}
3936
3937
3938//-----------------------------------------------------------------------------
3939void KMComposeWin::slotEncryptToggled(bool on)
3940{
3941 setEncryption( on, true /* set by the user */ );
3942 slotUpdateSignatureAndEncrypionStateIndicators();
3943}
3944
3945
3946//-----------------------------------------------------------------------------
3947void KMComposeWin::setEncryption( bool encrypt, bool setByUser )
3948{
3949 bool wasModified = isModified();
3950 if ( setByUser )
3951 setModified( true );
3952 if ( !mEncryptAction->isEnabled() )
3953 encrypt = false;
3954 // check if the user wants to encrypt messages to himself and if he defined
3955 // an encryption key for the current identity
3956 else if ( encrypt && encryptToSelf() && !mLastIdentityHasEncryptionKey ) {
3957 if ( setByUser ) {
3958 KMessageBox::sorry( this,
3959 i18n("<qt><p>You have requested that messages be "
3960 "encrypted to yourself, but the currently selected "
3961 "identity does not define an (OpenPGP or S/MIME) "
3962 "encryption key to use for this.</p>"
3963 "<p>Please select the key(s) to use "
3964 "in the identity configuration.</p>"
3965 "</qt>"),
3966 i18n("Undefined Encryption Key") );
3967 setModified( wasModified );
3968 }
3969 encrypt = false;
3970 }
3971
3972 // make sure the mEncryptAction is in the right state
3973 mEncryptAction->setChecked( encrypt );
3974
3975 // show the appropriate icon
3976 if ( encrypt )
3977 mEncryptAction->setIcon("encrypted");
3978 else
3979 mEncryptAction->setIcon("decrypted");
3980
3981 // mark the attachments for (no) encryption
3982 if ( canSignEncryptAttachments() ) {
3983 for ( KMAtmListViewItem* entry =
3984 static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
3985 entry;
3986 entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
3987 entry->setEncrypt( encrypt );
3988 }
3989}
3990
3991
3992//-----------------------------------------------------------------------------
3993void KMComposeWin::slotSignToggled(bool on)
3994{
3995 setSigning( on, true /* set by the user */ );
3996 slotUpdateSignatureAndEncrypionStateIndicators();
3997}
3998
3999
4000//-----------------------------------------------------------------------------
4001void KMComposeWin::setSigning( bool sign, bool setByUser )
4002{
4003 bool wasModified = isModified();
4004 if ( setByUser )
4005 setModified( true );
4006 if ( !mSignAction->isEnabled() )
4007 sign = false;
4008
4009 // check if the user defined a signing key for the current identity
4010 if ( sign && !mLastIdentityHasSigningKey ) {
4011 if ( setByUser ) {
4012 KMessageBox::sorry( this,
4013 i18n("<qt><p>In order to be able to sign "
4014 "this message you first have to "
4015 "define the (OpenPGP or S/MIME) signing key "
4016 "to use.</p>"
4017 "<p>Please select the key to use "
4018 "in the identity configuration.</p>"
4019 "</qt>"),
4020 i18n("Undefined Signing Key") );
4021 setModified( wasModified );
4022 }
4023 sign = false;
4024 }
4025
4026 // make sure the mSignAction is in the right state
4027 mSignAction->setChecked( sign );
4028
4029 // mark the attachments for (no) signing
4030 if ( canSignEncryptAttachments() ) {
4031 for ( KMAtmListViewItem* entry =
4032 static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
4033 entry;
4034 entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
4035 entry->setSign( sign );
4036 }
4037}
4038
4039
4040//-----------------------------------------------------------------------------
4041void KMComposeWin::slotWordWrapToggled(bool on)
4042{
4043 if (on)
4044 {
4045 mEditor->setWordWrap( TQTextEdit::FixedColumnWidth );
4046 mEditor->setWrapColumnOrWidth( GlobalSettings::self()->lineWrapWidth() );
4047 }
4048 else
4049 {
4050 mEditor->setWordWrap( TQTextEdit::WidgetWidth );
4051 }
4052}
4053
4054
4055void KMComposeWin::disableWordWrap()
4056{
4057 mEditor->setWordWrap( TQTextEdit::NoWrap );
4058}
4059
4060void KMComposeWin::disableRecipientNumberCheck()
4061{
4062 mCheckForRecipients = false;
4063}
4064
4065void KMComposeWin::disableForgottenAttachmentsCheck()
4066{
4067 mCheckForForgottenAttachments = false;
4068}
4069
4070void KMComposeWin::ignoreStickyFields()
4071{
4072 mIgnoreStickyFields = true;
4073 mBtnTransport->setChecked( false );
4074 mBtnDictionary->setChecked( false );
4075 mBtnIdentity->setChecked( false );
4076 mBtnTransport->setEnabled( false );
4077 mBtnDictionary->setEnabled( false );
4078 mBtnIdentity->setEnabled( false );
4079}
4080
4081//-----------------------------------------------------------------------------
4082void KMComposeWin::slotPrint()
4083{
4084 mMessageWasModified = isModified();
4085 connect( this, TQ_SIGNAL( applyChangesDone( bool ) ),
4086 this, TQ_SLOT( slotContinuePrint( bool ) ) );
4087 applyChanges( true );
4088}
4089
4090void KMComposeWin::slotContinuePrint( bool rc )
4091{
4092 disconnect( this, TQ_SIGNAL( applyChangesDone( bool ) ),
4093 this, TQ_SLOT( slotContinuePrint( bool ) ) );
4094
4095 if( rc ) {
4096 if ( mComposedMessages.isEmpty() ) {
4097 kdDebug(5006) << "Composing the message failed." << endl;
4098 return;
4099 }
4100 KMCommand *command = new KMPrintCommand( this, mComposedMessages.first() );
4101 command->start();
4102 setModified( mMessageWasModified );
4103 }
4104}
4105
4106//----------------------------------------------------------------------------
4107bool KMComposeWin::validateAddresses( TQWidget * parent, const TQString & addresses )
4108{
4109 TQString brokenAddress;
4110 KPIM::EmailParseResult errorCode = KMMessage::isValidEmailAddressList( KMMessage::expandAliases( addresses ), brokenAddress );
4111 if ( !( errorCode == KPIM::AddressOk || errorCode == KPIM::AddressEmpty ) ) {
4112 TQString errorMsg( "<qt><p><b>" + brokenAddress +
4113 "</b></p><p>" + KPIM::emailParseResultToString( errorCode ) +
4114 "</p></qt>" );
4115 KMessageBox::sorry( parent, errorMsg, i18n("Invalid Email Address") );
4116 return false;
4117 }
4118 return true;
4119}
4120
4121//----------------------------------------------------------------------------
4122void KMComposeWin::doSend( KMail::MessageSender::SendMethod method,
4123 KMComposeWin::SaveIn saveIn )
4124{
4125 if ( method != KMail::MessageSender::SendLater && kmkernel->isOffline() ) {
4126 KMessageBox::information( this,
4127 i18n("KMail is currently in offline mode,"
4128 "your messages will be kept in the outbox until you go online."),
4129 i18n("Online/Offline"), "kmailIsOffline" );
4130 mSendMethod = KMail::MessageSender::SendLater;
4131 } else {
4132 mSendMethod = method;
4133 }
4134 mSaveIn = saveIn;
4135
4136 if ( saveIn == KMComposeWin::None ) {
4137 if ( KPIM::getFirstEmailAddress( from() ).isEmpty() ) {
4138 if ( !( mShowHeaders & HDR_FROM ) ) {
4139 mShowHeaders |= HDR_FROM;
4140 rethinkFields( false );
4141 }
4142 mEdtFrom->setFocus();
4143 KMessageBox::sorry( this,
4144 i18n("You must enter your email address in the "
4145 "From: field. You should also set your email "
4146 "address for all identities, so that you do "
4147 "not have to enter it for each message.") );
4148 return;
4149 }
4150 if ( to().isEmpty() )
4151 {
4152 if ( cc().isEmpty() && bcc().isEmpty()) {
4153 if ( mEdtTo ) mEdtTo->setFocus();
4154 KMessageBox::information( this,
4155 i18n("You must specify at least one receiver,"
4156 "either in the To: field or as CC or as BCC.") );
4157 return;
4158 }
4159 else {
4160 if ( mEdtTo ) mEdtTo->setFocus();
4161 int rc =
4162 KMessageBox::questionYesNo( this,
4163 i18n("To field is missing."
4164 "Send message anyway?"),
4165 i18n("No To: specified") );
4166 if ( rc == KMessageBox::No ){
4167 return;
4168 }
4169 }
4170 }
4171
4172 // Validate the To:, CC: and BCC fields
4173 if ( !validateAddresses( this, to().stripWhiteSpace() ) ) {
4174 return;
4175 }
4176
4177 if ( !validateAddresses( this, cc().stripWhiteSpace() ) ) {
4178 return;
4179 }
4180
4181 if ( !validateAddresses( this, bcc().stripWhiteSpace() ) ) {
4182 return;
4183 }
4184
4185 if (subject().isEmpty())
4186 {
4187 mEdtSubject->setFocus();
4188 int rc =
4189 KMessageBox::questionYesNo( this,
4190 i18n("You did not specify a subject. "
4191 "Send message anyway?"),
4192 i18n("No Subject Specified"),
4193 i18n("S&end as Is"),
4194 i18n("&Specify the Subject"),
4195 "no_subject_specified" );
4196 if( rc == KMessageBox::No )
4197 {
4198 return;
4199 }
4200 }
4201
4202 if ( userForgotAttachment() )
4203 return;
4204 }
4205
4206 KCursorSaver busy(KBusyPtr::busy());
4207 mMsg->setDateToday();
4208
4209 // If a user sets up their outgoing messages preferences wrong and then
4210 // sends mail that gets 'stuck' in their outbox, they should be able to
4211 // rectify the problem by editing their outgoing preferences and
4212 // resending.
4213 // Hence this following conditional
4214 TQString hf = mMsg->headerField("X-KMail-Transport");
4215 if ((mTransport->currentText() != mTransport->text(0)) ||
4216 (!hf.isEmpty() && (hf != mTransport->text(0))))
4217 mMsg->setHeaderField("X-KMail-Transport", mTransport->currentText());
4218
4219 mDisableBreaking = ( saveIn != KMComposeWin::None );
4220
4221 const bool neverEncrypt = ( mDisableBreaking && GlobalSettings::self()->neverEncryptDrafts() )
4222 || mSigningAndEncryptionExplicitlyDisabled;
4223 connect( this, TQ_SIGNAL( applyChangesDone( bool ) ),
4224 TQ_SLOT( slotContinueDoSend( bool ) ) );
4225
4226 if ( mEditor->textFormat() == TQt::RichText )
4227 mMsg->setHeaderField( "X-KMail-Markup", "true" );
4228 else
4229 mMsg->removeHeaderField( "X-KMail-Markup" );
4230 if ( mEditor->textFormat() == TQt::RichText && inlineSigningEncryptionSelected() ) {
4231 TQString keepBtnText = mEncryptAction->isChecked() ?
4232 mSignAction->isChecked() ? i18n( "&Keep markup, do not sign/encrypt" )
4233 : i18n( "&Keep markup, do not encrypt" )
4234 : i18n( "&Keep markup, do not sign" );
4235 TQString yesBtnText = mEncryptAction->isChecked() ?
4236 mSignAction->isChecked() ? i18n("Sign/Encrypt (delete markup)")
4237 : i18n( "Encrypt (delete markup)" )
4238 : i18n( "Sign (delete markup)" );
4239 int ret = KMessageBox::warningYesNoCancel(this,
4240 i18n("<qt><p>Inline signing/encrypting of HTML messages is not possible;</p>"
4241 "<p>do you want to delete your markup?</p></qt>"),
4242 i18n("Sign/Encrypt Message?"),
4243 KGuiItem( yesBtnText ),
4244 KGuiItem( keepBtnText ) );
4245 if ( KMessageBox::Cancel == ret )
4246 return;
4247 if ( KMessageBox::No == ret ) {
4248 mEncryptAction->setChecked(false);
4249 mSignAction->setChecked(false);
4250 }
4251 else {
4252 toggleMarkup(false);
4253 }
4254 }
4255
4256 if (neverEncrypt && saveIn != KMComposeWin::None ) {
4257 // we can't use the state of the mail itself, to remember the
4258 // signing and encryption state, so let's add a header instead
4259 mMsg->setHeaderField( "X-KMail-SignatureActionEnabled", mSignAction->isChecked()? "true":"false" );
4260 mMsg->setHeaderField( "X-KMail-EncryptActionEnabled", mEncryptAction->isChecked()? "true":"false" );
4261 mMsg->setHeaderField( "X-KMail-CryptoMessageFormat", TQString::number( cryptoMessageFormat() ) );
4262 } else {
4263 mMsg->removeHeaderField( "X-KMail-SignatureActionEnabled" );
4264 mMsg->removeHeaderField( "X-KMail-EncryptActionEnabled" );
4265 mMsg->removeHeaderField( "X-KMail-CryptoMessageFormat" );
4266 }
4267
4268
4269 kdDebug(5006) << "KMComposeWin::doSend() - calling applyChanges()"
4270 << endl;
4271 applyChanges( neverEncrypt );
4272}
4273
4274bool KMComposeWin::saveDraftOrTemplate( const TQString &folderName,
4275 KMMessage *msg )
4276{
4277 KMFolder *theFolder = 0, *imapTheFolder = 0;
4278 // get the draftsFolder
4279 if ( !folderName.isEmpty() ) {
4280 theFolder = kmkernel->folderMgr()->findIdString( folderName );
4281 if ( theFolder == 0 )
4282 // This is *NOT* supposed to be "imapDraftsFolder", because a
4283 // dIMAP folder works like a normal folder
4284 theFolder = kmkernel->dimapFolderMgr()->findIdString( folderName );
4285 if ( theFolder == 0 )
4286 imapTheFolder = kmkernel->imapFolderMgr()->findIdString( folderName );
4287 if ( !theFolder && !imapTheFolder ) {
4288 const KPIM::Identity & id = kmkernel->identityManager()
4289 ->identityForUoidOrDefault( msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt() );
4290 KMessageBox::information( 0,
4291 i18n("The custom drafts or templates folder for "
4292 "identify \"%1\" does not exist (anymore); "
4293 "therefore, the default drafts or templates "
4294 "folder will be used.")
4295 .arg( id.identityName() ) );
4296 }
4297 }
4298 if ( imapTheFolder && imapTheFolder->noContent() )
4299 imapTheFolder = 0;
4300
4301 bool didOpen = false;
4302 if ( theFolder == 0 ) {
4303 theFolder = ( mSaveIn==KMComposeWin::Drafts ?
4304 kmkernel->draftsFolder() : kmkernel->templatesFolder() );
4305 } else {
4306 //XXX this looks really, really fishy
4307 theFolder->open( "composer" );
4308 didOpen = true;
4309 }
4310 kdDebug(5006) << k_funcinfo << "theFolder=" << theFolder->name() << endl;
4311 if ( imapTheFolder )
4312 kdDebug(5006) << k_funcinfo << "imapTheFolder=" << imapTheFolder->name() << endl;
4313
4314 bool sentOk = !( theFolder->addMsg( msg ) );
4315
4316 // Ensure the message is correctly and fully parsed
4317 theFolder->unGetMsg( theFolder->count() - 1 );
4318 msg = theFolder->getMsg( theFolder->count() - 1 );
4319 // Does that assignment needs to be propagated out to the caller?
4320 // Assuming the send is OK, the iterator is set to 0 immediately afterwards.
4321 if ( imapTheFolder ) {
4322 // move the message to the imap-folder and highlight it
4323 imapTheFolder->moveMsg( msg );
4324 (static_cast<KMFolderImap*>( imapTheFolder->storage() ))->getFolder();
4325 }
4326
4327 if ( didOpen )
4328 theFolder->close( "composer" );
4329 return sentOk;
4330}
4331
4332void KMComposeWin::slotContinueDoSend( bool sentOk )
4333{
4334 kdDebug(5006) << "KMComposeWin::slotContinueDoSend( " << sentOk << " )"
4335 << endl;
4336 disconnect( this, TQ_SIGNAL( applyChangesDone( bool ) ),
4337 this, TQ_SLOT( slotContinueDoSend( bool ) ) );
4338
4339 if ( !sentOk ) {
4340 mDisableBreaking = false;
4341 return;
4342 }
4343
4344 for ( TQValueVector<KMMessage*>::iterator it = mComposedMessages.begin() ; it != mComposedMessages.end() ; ++it ) {
4345
4346 // remove fields that contain no data (e.g. an empty Cc: or Bcc:)
4347 (*it)->cleanupHeader();
4348
4349 // needed for imap
4350 (*it)->setComplete( true );
4351
4352 if ( mSaveIn==KMComposeWin::Drafts ) {
4353 sentOk = saveDraftOrTemplate( (*it)->drafts(), (*it) );
4354 } else if ( mSaveIn==KMComposeWin::Templates ) {
4355 sentOk = saveDraftOrTemplate( (*it)->templates(), (*it) );
4356 } else {
4357 (*it)->setTo( KMMessage::expandAliases( to() ));
4358 (*it)->setCc( KMMessage::expandAliases( cc() ));
4359 if( !mComposer->originalBCC().isEmpty() )
4360 (*it)->setBcc( KMMessage::expandAliases( mComposer->originalBCC() ));
4361 TQString recips = (*it)->headerField( "X-KMail-Recipients" );
4362 if( !recips.isEmpty() ) {
4363 (*it)->setHeaderField( "X-KMail-Recipients", KMMessage::expandAliases( recips ), KMMessage::Address );
4364 }
4365 (*it)->cleanupHeader();
4366 sentOk = kmkernel->msgSender()->send((*it), mSendMethod);
4367 }
4368
4369 if (!sentOk)
4370 return;
4371
4372 *it = 0; // don't kill it later...
4373 }
4374
4375 RecentAddresses::self( KMKernel::config() )->add( bcc() );
4376 RecentAddresses::self( KMKernel::config() )->add( cc() );
4377 RecentAddresses::self( KMKernel::config() )->add( to() );
4378
4379 setModified( false );
4380 mAutoDeleteMsg = false;
4381 mFolder = 0;
4382 cleanupAutoSave();
4383 close();
4384 return;
4385}
4386
4387bool KMComposeWin::checkTransport() const
4388{
4389 if ( KMail::TransportManager::transportNames().isEmpty() ) {
4390 KMessageBox::information( mMainWidget,
4391 i18n("Please create an account for sending and try again.") );
4392 return false;
4393 }
4394 return true;
4395
4396}
4397
4398//----------------------------------------------------------------------------
4399void KMComposeWin::slotSendLater()
4400{
4401 if ( !checkTransport() )
4402 return;
4403 if ( !checkRecipientNumber() )
4404 return;
4405 if ( mEditor->checkExternalEditorFinished() )
4406 doSend( KMail::MessageSender::SendLater );
4407}
4408
4409
4410//----------------------------------------------------------------------------
4411void KMComposeWin::slotSaveDraft() {
4412 if ( mEditor->checkExternalEditorFinished() )
4413 doSend( KMail::MessageSender::SendLater, KMComposeWin::Drafts );
4414}
4415
4416//----------------------------------------------------------------------------
4417void KMComposeWin::slotSaveTemplate() {
4418 if ( mEditor->checkExternalEditorFinished() )
4419 doSend( KMail::MessageSender::SendLater, KMComposeWin::Templates );
4420}
4421
4422//----------------------------------------------------------------------------
4423void KMComposeWin::slotSendNowVia( int item )
4424{
4425 TQStringList availTransports= KMail::TransportManager::transportNames();
4426 TQString customTransport = availTransports[ item ];
4427
4428 mTransport->setCurrentText( customTransport );
4429 slotSendNow();
4430}
4431
4432//----------------------------------------------------------------------------
4433void KMComposeWin::slotSendLaterVia( int item )
4434{
4435 TQStringList availTransports= KMail::TransportManager::transportNames();
4436 TQString customTransport = availTransports[ item ];
4437
4438 mTransport->setCurrentText( customTransport );
4439 slotSendLater();
4440}
4441
4442
4443//----------------------------------------------------------------------------
4444void KMComposeWin::slotSendNow() {
4445 if ( !mEditor->checkExternalEditorFinished() )
4446 return;
4447 if ( !checkTransport() )
4448 return;
4449 if ( !checkRecipientNumber() )
4450 return;
4451 if ( GlobalSettings::self()->confirmBeforeSend() )
4452 {
4453 int rc = KMessageBox::warningYesNoCancel( mMainWidget,
4454 i18n("About to send email..."),
4455 i18n("Send Confirmation"),
4456 i18n("&Send Now"),
4457 i18n("Send &Later") );
4458
4459 if ( rc == KMessageBox::Yes )
4460 doSend( KMail::MessageSender::SendImmediate );
4461 else if ( rc == KMessageBox::No )
4462 doSend( KMail::MessageSender::SendLater );
4463 }
4464 else
4465 doSend( KMail::MessageSender::SendImmediate );
4466}
4467
4468
4469//----------------------------------------------------------------------------
4470bool KMComposeWin::checkRecipientNumber() const
4471{
4472 uint thresHold = GlobalSettings::self()->recipientThreshold();
4473 if ( mCheckForRecipients &&
4474 GlobalSettings::self()->tooManyRecipients() &&
4475 mRecipientsEditor->recipients().count() > thresHold ) {
4476 if ( KMessageBox::questionYesNo( mMainWidget,
4477 i18n("You are trying to send the mail to more than %1 recipients. Send message anyway?").arg(thresHold),
4478 i18n("Too many receipients"),
4479 i18n("&Send as Is"),
4480 i18n("&Edit Recipients")) == KMessageBox::No ) {
4481 return false;
4482 }
4483 }
4484 return true;
4485}
4486
4487
4488//----------------------------------------------------------------------------
4489void KMComposeWin::slotAppendSignature()
4490{
4491 insertSignature();
4492}
4493
4494//----------------------------------------------------------------------------
4495void KMComposeWin::slotPrependSignature()
4496{
4497 insertSignature( Prepend );
4498}
4499
4500//----------------------------------------------------------------------------
4501void KMComposeWin::slotInsertSignatureAtCursor()
4502{
4503 insertSignature( AtCursor );
4504}
4505
4506//----------------------------------------------------------------------------
4507void KMComposeWin::insertSignature( SignaturePlacement placement )
4508{
4509 bool mod = mEditor->isModified();
4510
4511 const KPIM::Identity &ident =
4512 kmkernel->identityManager()->
4513 identityForUoidOrDefault( mIdentity->currentIdentity() );
4514
4515 mOldSigText = GlobalSettings::self()->prependSignature()? ident.signature().rawText() : ident.signatureText();
4516
4517 if( !mOldSigText.isEmpty() )
4518 {
4519 mEditor->sync();
4520 int paragraph, index;
4521 mEditor->getCursorPosition( &paragraph, &index );
4522 index = mEditor->indexOfCurrentLineStart( paragraph, index );
4523
4524 switch( placement ) {
4525 case Append:
4526 mEditor->setText( mEditor->text() + mOldSigText );
4527 break;
4528 case Prepend:
4529 mOldSigText = "\n\n" + mOldSigText + "\n";
4530 mEditor->insertAt( mOldSigText, paragraph, index );
4531 break;
4532 case AtCursor:
4533
4534 // If there is text in the same line, add a newline so that the stuff in
4535 // the current line moves after the signature. Also remove a leading newline, it is not
4536 // needed here.
4537 if ( mEditor->paragraphLength( paragraph ) > 0 )
4538 mOldSigText = mOldSigText + "\n";
4539 if ( mOldSigText.startsWith( "\n" ) )
4540 mOldSigText = mOldSigText.remove( 0, 1 );
4541
4542 // If we are inserting into a wordwrapped line, add a newline at the start to make
4543 // the text edit hard-wrap the line here
4544 if ( index != 0 )
4545 mOldSigText = "\n" + mOldSigText;
4546
4547 mEditor->insertAt( mOldSigText, paragraph, index );
4548 break;
4549 }
4550 mEditor->update();
4551 mEditor->setModified(mod);
4552
4553 if ( mPreserveUserCursorPosition ) {
4554 mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
4555 // Only keep the cursor from the mMsg *once* based on the
4556 // preserve-cursor-position setting; this handles the case where
4557 // the message comes from a template with a specific cursor
4558 // position set and the signature is appended automatically.
4559 mPreserveUserCursorPosition = false;
4560 } else {
4561 // for append and prepend, move the cursor to 0,0, for insertAt,
4562 // keep it in the same row, but move to first column
4563 if ( index == 0 ) {
4564 mEditor->setCursorPosition( paragraph, 0 );
4565 } else {
4566 // For word-wrapped lines, we have created a new paragraph, so change to that one
4567 mEditor->setCursorPosition( paragraph + 1, 0 );
4568 }
4569 if ( placement == Prepend || placement == Append )
4570 mEditor->setContentsPos( 0, 0 );
4571 }
4572 mEditor->sync();
4573 }
4574}
4575
4576//-----------------------------------------------------------------------------
4577void KMComposeWin::slotHelp()
4578{
4579 tdeApp->invokeHelp();
4580}
4581
4582//-----------------------------------------------------------------------------
4583void KMComposeWin::slotCleanSpace()
4584{
4585 // Originally we simply used the KEdit::cleanWhiteSpace() method,
4586 // but that code doesn't handle quoted-lines or signatures, so instead
4587 // we now simply use regexp's to squeeze sequences of tabs and spaces
4588 // into a single space, and make sure all our lines are single-spaced.
4589 //
4590 // Yes, extra space in a quote string is squeezed.
4591 // Signatures are respected (i.e. not cleaned).
4592
4593 TQString s;
4594 if ( mEditor->hasMarkedText() ) {
4595 s = mEditor->markedText();
4596 if( s.isEmpty() )
4597 return;
4598 } else {
4599 s = mEditor->text();
4600 }
4601
4602 // Remove the signature for now.
4603 TQString sig;
4604 bool restore = false;
4605 const KPIM::Identity & ident =
4606 kmkernel->identityManager()->identityForUoid( mId );
4607 if ( !ident.isNull() ) {
4608 sig = ident.signatureText();
4609 if( !sig.isEmpty() ) {
4610 if( s.endsWith( sig ) ) {
4611 s.truncate( s.length() - sig.length() );
4612 restore = true;
4613 }
4614 }
4615 }
4616
4617 // Squeeze tabs and spaces
4618 TQRegExp squeeze( "[\t ]+" );
4619 s.replace( squeeze, TQChar( ' ' ) );
4620
4621 // Remove trailing whitespace
4622 TQRegExp trailing( "\\s+$" );
4623 s.replace( trailing, TQChar( '\n' ) );
4624
4625 // Single space lines
4626 TQRegExp singleSpace( "[\n]{2,}" );
4627 s.replace( singleSpace, TQChar( '\n' ) );
4628
4629 // Restore the signature
4630 if ( restore )
4631 s.append( sig );
4632
4633 // Put the new text in place.
4634 // The lines below do not clear the undo history, but unfortuately cause
4635 // the side-effect that you need to press Ctrl-Z twice (first Ctrl-Z will
4636 // show cleared text area) to get back the original, pre-cleaned text.
4637 // If you use mEditor->setText( s ) then the undo history is cleared so
4638 // that isn't a good solution either.
4639 // TODO: is TQt4 better at handling the undo history??
4640 if ( !mEditor->hasMarkedText() )
4641 mEditor->clear();
4642 mEditor->insert( s );
4643}
4644
4645//-----------------------------------------------------------------------------
4646void KMComposeWin::slotToggleMarkup()
4647{
4648 if ( markupAction->isChecked() ) {
4649 mHtmlMarkup = true;
4650 toolBar("htmlToolBar")->show();
4651 // markup will be toggled as soon as markup is actually used
4652 fontChanged( mEditor->currentFont() ); // set buttons in correct position
4653 mSaveFont = mEditor->currentFont();
4654 }
4655 else
4656 toggleMarkup(false);
4657
4658}
4659//-----------------------------------------------------------------------------
4660void KMComposeWin::toggleMarkup(bool markup)
4661{
4662 if ( markup ) {
4663 if ( !mUseHTMLEditor ) {
4664 kdDebug(5006) << "setting RichText editor" << endl;
4665 mUseHTMLEditor = true; // set it directly to true. setColor hits another toggleMarkup
4666 mHtmlMarkup = true;
4667
4668 // set all highlighted text caused by spelling back to black
4669 int paraFrom, indexFrom, paraTo, indexTo;
4670 mEditor->getSelection ( &paraFrom, &indexFrom, &paraTo, &indexTo);
4671 mEditor->selectAll();
4672 // save the buttonstates because setColor calls fontChanged
4673 bool _bold = textBoldAction->isChecked();
4674 bool _italic = textItalicAction->isChecked();
4675 mEditor->setColor(TQColor(0,0,0));
4676 textBoldAction->setChecked(_bold);
4677 textItalicAction->setChecked(_italic);
4678 mEditor->setSelection ( paraFrom, indexFrom, paraTo, indexTo);
4679
4680 mEditor->setTextFormat(TQt::RichText);
4681 mEditor->setModified(true);
4682 markupAction->setChecked(true);
4683 toolBar( "htmlToolBar" )->show();
4684 mEditor->deleteAutoSpellChecking();
4685 mAutoSpellCheckingAction->setChecked(false);
4686 slotAutoSpellCheckingToggled(false);
4687 }
4688 } else { // markup is to be turned off
4689 kdDebug(5006) << "setting PlainText editor" << endl;
4690 mHtmlMarkup = false;
4691 toolBar("htmlToolBar")->hide();
4692 if ( mUseHTMLEditor ) { // it was turned on
4693 mUseHTMLEditor = false;
4694 mEditor->setTextFormat(TQt::PlainText);
4695 TQString text = mEditor->text();
4696 mEditor->setText(text); // otherwise the text still looks formatted
4697 mEditor->setModified(true);
4698 slotAutoSpellCheckingToggled(true);
4699 }
4700 }
4701}
4702
4703void KMComposeWin::htmlToolBarVisibilityChanged( bool visible )
4704{
4705 // disable markup if the user hides the HTML toolbar
4706 if ( !visible ) {
4707 markupAction->setChecked( false );
4708 toggleMarkup( false );
4709 }
4710}
4711
4712void KMComposeWin::slotSubjectTextSpellChecked()
4713{
4714 mSubjectTextWasSpellChecked = true;
4715}
4716
4717//-----------------------------------------------------------------------------
4718void KMComposeWin::slotAutoSpellCheckingToggled( bool on )
4719{
4720 if ( mEditor->autoSpellChecking(on) == -1 ) {
4721 mAutoSpellCheckingAction->setChecked(false); // set it to false again
4722 }
4723
4724 TQString temp;
4725 if ( on )
4726 temp = i18n( "Spellcheck: on" );
4727 else
4728 temp = i18n( "Spellcheck: off" );
4729 statusBar()->changeItem( temp, 3 );
4730}
4731//-----------------------------------------------------------------------------
4732void KMComposeWin::slotSpellcheck()
4733{
4734 if (mSpellCheckInProgress) return;
4735 mSubjectTextWasSpellChecked = false;
4736 mSpellCheckInProgress=true;
4737 /*
4738 connect (mEditor, TQ_SIGNAL (spellcheck_progress (unsigned)),
4739 this, TQ_SLOT (spell_progress (unsigned)));
4740 */
4741
4742 mEditor->spellcheck();
4743}
4744//-----------------------------------------------------------------------------
4745void KMComposeWin::slotUpdateSignatureActions()
4746{
4747 //Check if an identity has signature or not and turn on/off actions in the
4748 //edit menu accordingly.
4749 const KPIM::Identity & ident =
4750 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
4751 TQString sig = ident.signatureText();
4752
4753 if ( sig.isEmpty() ) {
4754 mAppendSignatureAction->setEnabled( false );
4755 mPrependSignatureAction->setEnabled( false );
4756 mInsertSignatureAction->setEnabled( false );
4757 }
4758 else {
4759 mAppendSignatureAction->setEnabled( true );
4760 mPrependSignatureAction->setEnabled( true );
4761 mInsertSignatureAction->setEnabled( true );
4762 }
4763}
4764
4765void KMComposeWin::polish()
4766{
4767 // Ensure the html toolbar is appropriately shown/hidden
4768 markupAction->setChecked(mHtmlMarkup);
4769 if (mHtmlMarkup)
4770 toolBar("htmlToolBar")->show();
4771 else
4772 toolBar("htmlToolBar")->hide();
4773 KMail::Composer::polish();
4774}
4775
4776//-----------------------------------------------------------------------------
4777void KMComposeWin::slotSpellcheckDone(int result)
4778{
4779 kdDebug(5006) << "spell check complete: result = " << result << endl;
4780 mSpellCheckInProgress=false;
4781
4782 switch( result )
4783 {
4784 case KS_CANCEL:
4785 statusBar()->changeItem(i18n(" Spell check canceled."),0);
4786 break;
4787 case KS_STOP:
4788 statusBar()->changeItem(i18n(" Spell check stopped."),0);
4789 break;
4790 default:
4791 statusBar()->changeItem(i18n(" Spell check complete."),0);
4792 break;
4793 }
4794 TQTimer::singleShot( 2000, this, TQ_SLOT(slotSpellcheckDoneClearStatus()) );
4795}
4796
4797void KMComposeWin::slotSpellcheckDoneClearStatus()
4798{
4799 statusBar()->changeItem("", 0);
4800}
4801
4802
4803//-----------------------------------------------------------------------------
4804void KMComposeWin::slotIdentityChanged( uint uoid )
4805{
4806 const KPIM::Identity & ident =
4807 kmkernel->identityManager()->identityForUoid( uoid );
4808 if( ident.isNull() ) return;
4809
4810 //Turn on/off signature actions if identity has no signature.
4811 slotUpdateSignatureActions();
4812
4813 if( !ident.fullEmailAddr().isNull() )
4814 mEdtFrom->setText(ident.fullEmailAddr());
4815 // make sure the From field is shown if it does not contain a valid email address
4816 if ( KPIM::getFirstEmailAddress( from() ).isEmpty() )
4817 mShowHeaders |= HDR_FROM;
4818 if ( mEdtReplyTo ) mEdtReplyTo->setText(ident.replyToAddr());
4819
4820 if ( mRecipientsEditor ) {
4821 // remove BCC of old identity and add BCC of new identity (if they differ)
4822 const KPIM::Identity & oldIdentity =
4823 kmkernel->identityManager()->identityForUoidOrDefault( mId );
4824 if ( oldIdentity.bcc() != ident.bcc() ) {
4825 mRecipientsEditor->removeRecipient( oldIdentity.bcc(), Recipient::Bcc );
4826 mRecipientsEditor->addRecipient( ident.bcc(), Recipient::Bcc );
4827 mRecipientsEditor->setFocusBottom();
4828 }
4829 }
4830
4831 // don't overwrite the BCC field under certain circomstances
4832 // NOT edited and preset BCC from the identity
4833 if( mEdtBcc && !mEdtBcc->edited() && !ident.bcc().isEmpty() ) {
4834 // BCC NOT empty AND contains a diff adress then the preset BCC
4835 // of the new identity
4836 if( !mEdtBcc->text().isEmpty() && mEdtBcc->text() != ident.bcc() && !mEdtBcc->edited() ) {
4837 mEdtBcc->setText( ident.bcc() );
4838 } else {
4839 // user type into the editbox an address that != to the preset bcc
4840 // of the identity, we assume that since the user typed it
4841 // they want to keep it
4842 if ( mEdtBcc->text() != ident.bcc() && !mEdtBcc->text().isEmpty() ) {
4843 TQString temp_string( mEdtBcc->text() + TQString::fromLatin1(",") + ident.bcc() );
4844 mEdtBcc->setText( temp_string );
4845 } else {
4846 // if the user typed the same address as the preset BCC
4847 // from the identity we will overwrite it to avoid duplicates.
4848 mEdtBcc->setText( ident.bcc() );
4849 }
4850 }
4851 }
4852 // user edited the bcc box and has a preset bcc in the identity
4853 // we will append whatever the user typed to the preset address
4854 // allowing the user to keep all addresses
4855 if( mEdtBcc && mEdtBcc->edited() && !ident.bcc().isEmpty() ) {
4856 if( !mEdtBcc->text().isEmpty() ) {
4857 TQString temp_string ( mEdtBcc->text() + TQString::fromLatin1(",") + ident.bcc() );
4858 mEdtBcc->setText( temp_string );
4859 } else {
4860 mEdtBcc->setText( ident.bcc() );
4861 }
4862 }
4863 // user typed nothing and the identity does not have a preset bcc
4864 // we then reset the value to get rid of any previous
4865 // values if the user changed identity mid way through.
4866 if( mEdtBcc && !mEdtBcc->edited() && ident.bcc().isEmpty() ) {
4867 mEdtBcc->setText( ident.bcc() );
4868 }
4869 // make sure the BCC field is shown because else it's ignored
4870 if ( !ident.bcc().isEmpty() ) {
4871 mShowHeaders |= HDR_BCC;
4872 }
4873
4874 if ( ident.organization().isEmpty() )
4875 mMsg->removeHeaderField("Organization");
4876 else
4877 mMsg->setHeaderField("Organization", ident.organization());
4878
4879 if (!ident.isXFaceEnabled() || ident.xface().isEmpty())
4880 mMsg->removeHeaderField("X-Face");
4881 else
4882 {
4883 TQString xface = ident.xface();
4884 if (!xface.isEmpty())
4885 {
4886 int numNL = ( xface.length() - 1 ) / 70;
4887 for ( int i = numNL; i > 0; --i )
4888 xface.insert( i*70, "\n\t" );
4889 mMsg->setHeaderField("X-Face", xface);
4890 }
4891 }
4892
4893 if ( !mBtnTransport->isChecked() && !mIgnoreStickyFields ) {
4894 TQString transp = ident.transport();
4895 if ( transp.isEmpty() )
4896 {
4897 mMsg->removeHeaderField("X-KMail-Transport");
4898 transp = GlobalSettings::self()->defaultTransport();
4899 }
4900 else
4901 mMsg->setHeaderField("X-KMail-Transport", transp);
4902 setTransport( transp );
4903 }
4904
4905 if ( !mBtnDictionary->isChecked() && !mIgnoreStickyFields ) {
4906 mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
4907 }
4908
4909 if ( !mBtnFcc->isChecked() && !mPreventFccOverwrite ) {
4910 setFcc( ident.fcc() );
4911 }
4912
4913 TQString edtText = mEditor->text();
4914
4915 if ( mOldSigText.isEmpty() ) {
4916 const KPIM::Identity &id =
4917 kmkernel->
4918 identityManager()->
4919 identityForUoidOrDefault( mMsg->headerField( "X-KMail-Identity" ).
4920 stripWhiteSpace().toUInt() );
4921 mOldSigText = GlobalSettings::self()->prependSignature() ? id.signature().rawText() : id.signatureText();
4922 }
4923
4924
4925 if ( !GlobalSettings::prependSignature() ) {
4926 // try to truncate the old sig
4927 // First remove any trailing whitespace
4928 while ( !edtText.isEmpty() && edtText[edtText.length()-1].isSpace() )
4929 edtText.truncate( edtText.length() - 1 );
4930 // From the sig too, just in case
4931 while ( !mOldSigText.isEmpty() && mOldSigText[mOldSigText.length()-1].isSpace() )
4932 mOldSigText.truncate( mOldSigText.length() - 1 );
4933
4934 if ( edtText.endsWith( mOldSigText ) )
4935 edtText.truncate( edtText.length() - mOldSigText.length() );
4936
4937 // now append the new sig
4938 mOldSigText = ident.signatureText();
4939 if( ( !mOldSigText.isEmpty() ) &&
4940 ( GlobalSettings::self()->autoTextSignature() == "auto" ) ) {
4941 edtText.append( mOldSigText );
4942 }
4943 mEditor->setText( edtText );
4944 } else {
4945 const int pos = edtText.find( mOldSigText );
4946 if ( pos >= 0 && !mOldSigText.isEmpty() ) {
4947 const int oldLength = mOldSigText.length();
4948 mOldSigText = "\n\n"+ ident.signature().rawText() + "\n"; // see insertSignature()
4949 edtText = edtText.replace( pos, oldLength, mOldSigText );
4950 mEditor->setText( edtText );
4951 } else {
4952 insertSignature( Append );
4953 }
4954 }
4955
4956 // disable certain actions if there is no PGP user identity set
4957 // for this profile
4958 bool bNewIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
4959 bool bNewIdentityHasEncryptionKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
4960 mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
4961 !ident.pgpEncryptionKey().isEmpty() );
4962 // save the state of the sign and encrypt button
4963 if ( !bNewIdentityHasEncryptionKey && mLastIdentityHasEncryptionKey ) {
4964 mLastEncryptActionState = mEncryptAction->isChecked();
4965 setEncryption( false );
4966 }
4967 if ( !bNewIdentityHasSigningKey && mLastIdentityHasSigningKey ) {
4968 mLastSignActionState = mSignAction->isChecked();
4969 setSigning( false );
4970 }
4971 // restore the last state of the sign and encrypt button
4972 if ( bNewIdentityHasEncryptionKey && !mLastIdentityHasEncryptionKey )
4973 setEncryption( mLastEncryptActionState );
4974 if ( bNewIdentityHasSigningKey && !mLastIdentityHasSigningKey )
4975 setSigning( mLastSignActionState );
4976
4977 mLastIdentityHasSigningKey = bNewIdentityHasSigningKey;
4978 mLastIdentityHasEncryptionKey = bNewIdentityHasEncryptionKey;
4979
4980 setModified( true );
4981 mId = uoid;
4982
4983 // make sure the From and BCC fields are shown if necessary
4984 rethinkFields( false );
4985}
4986
4987//-----------------------------------------------------------------------------
4988void KMComposeWin::slotSpellcheckConfig()
4989{
4990 KDialogBase dlg(KDialogBase::Plain, i18n("Spellchecker"),
4991 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok,
4992 this, 0, true, true );
4993 KWin twin;
4994 TQTabDialog qtd (this, "tabdialog", true);
4995 KSpellConfig mKSpellConfig (&qtd);
4996 mKSpellConfig.layout()->setMargin( KDialog::marginHint() );
4997
4998 qtd.addTab (&mKSpellConfig, i18n("Spellchecker"));
4999 qtd.setCancelButton ();
5000
5001 twin.setIcons (qtd.winId(), tdeApp->icon(), tdeApp->miniIcon());
5002 qtd.setCancelButton(KStdGuiItem::cancel().text());
5003 qtd.setOkButton(KStdGuiItem::ok().text());
5004
5005 if (qtd.exec())
5006 mKSpellConfig.writeGlobalSettings();
5007}
5008
5009//-----------------------------------------------------------------------------
5010void KMComposeWin::slotStatusMessage(const TQString &message)
5011{
5012 statusBar()->changeItem( message, 0 );
5013}
5014
5015void KMComposeWin::slotEditToolbars()
5016{
5017 saveMainWindowSettings(KMKernel::config(), "Composer");
5018 KEditToolbar dlg(guiFactory(), this);
5019
5020 connect( &dlg, TQ_SIGNAL(newToolbarConfig()),
5021 TQ_SLOT(slotUpdateToolbars()) );
5022
5023 dlg.exec();
5024}
5025
5026void KMComposeWin::slotUpdateToolbars()
5027{
5028 createGUI("kmcomposerui.rc");
5029 applyMainWindowSettings(KMKernel::config(), "Composer");
5030}
5031
5032void KMComposeWin::slotEditKeys()
5033{
5034 KKeyDialog::configure( actionCollection(),
5035 false /*don't allow one-letter shortcuts*/
5036 );
5037}
5038
5039void KMComposeWin::setReplyFocus( bool hasMessage )
5040{
5041 mEditor->setFocus();
5042 if ( hasMessage ) {
5043 if( mMsg->getCursorPos() ) {
5044 mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
5045 } else {
5046 mEditor->setCursorPosition( 1, 0 );
5047 }
5048 }
5049}
5050
5051void KMComposeWin::setFocusToSubject()
5052{
5053 mEdtSubject->setFocus();
5054}
5055
5056int KMComposeWin::autoSaveInterval() const
5057{
5058 return GlobalSettings::self()->autosaveInterval() * 1000 * 60;
5059}
5060
5061void KMComposeWin::initAutoSave()
5062{
5063 kdDebug(5006) << k_funcinfo << endl;
5064 // make sure the autosave folder exists
5065 KMFolderMaildir::createMaildirFolders( KMKernel::localDataPath() + "autosave" );
5066 if ( mAutoSaveFilename.isEmpty() ) {
5067 mAutoSaveFilename = KMFolderMaildir::constructValidFileName();
5068 }
5069
5070 updateAutoSave();
5071}
5072
5073void KMComposeWin::updateAutoSave()
5074{
5075 if ( autoSaveInterval() == 0 ) {
5076 delete mAutoSaveTimer; mAutoSaveTimer = 0;
5077 }
5078 else {
5079 if ( !mAutoSaveTimer ) {
5080 mAutoSaveTimer = new TQTimer( this, "mAutoSaveTimer" );
5081 connect( mAutoSaveTimer, TQ_SIGNAL( timeout() ),
5082 this, TQ_SLOT( autoSaveMessage() ) );
5083 }
5084 mAutoSaveTimer->start( autoSaveInterval() );
5085 }
5086}
5087
5088void KMComposeWin::setAutoSaveFilename( const TQString & filename )
5089{
5090 mAutoSaveFilename = filename;
5091}
5092
5093void KMComposeWin::cleanupAutoSave()
5094{
5095 delete mAutoSaveTimer; mAutoSaveTimer = 0;
5096 if ( !mAutoSaveFilename.isEmpty() ) {
5097 kdDebug(5006) << k_funcinfo << "deleting autosave file "
5098 << mAutoSaveFilename << endl;
5099 KMFolderMaildir::removeFile( KMKernel::localDataPath() + "autosave",
5100 mAutoSaveFilename );
5101 mAutoSaveFilename = TQString();
5102 }
5103}
5104
5105void KMComposeWin::slotCompletionModeChanged( TDEGlobalSettings::Completion mode)
5106{
5107 GlobalSettings::self()->setCompletionMode( (int) mode );
5108
5109 // sync all the lineedits to the same completion mode
5110 mEdtFrom->setCompletionMode( mode );
5111 mEdtReplyTo->setCompletionMode( mode );
5112 if ( mClassicalRecipients ) {
5113 mEdtTo->setCompletionMode( mode );
5114 mEdtCc->setCompletionMode( mode );
5115 mEdtBcc->setCompletionMode( mode );
5116 }else
5117 mRecipientsEditor->setCompletionMode( mode );
5118}
5119
5120void KMComposeWin::slotConfigChanged()
5121{
5122 readConfig( true /*reload*/);
5123 updateAutoSave();
5124 rethinkFields();
5125 slotWordWrapToggled( mWordWrapAction->isChecked() );
5126}
5127
5128/*
5129* checks if the drafts-folder has been deleted
5130* that is not nice so we set the system-drafts-folder
5131*/
5132void KMComposeWin::slotFolderRemoved(KMFolder* folder)
5133{
5134 // TODO: need to handle templates here?
5135 if ( (mFolder) && (folder->idString() == mFolder->idString()) )
5136 {
5137 mFolder = kmkernel->draftsFolder();
5138 kdDebug(5006) << "restoring drafts to " << mFolder->idString() << endl;
5139 }
5140 if (mMsg) mMsg->setParent(0);
5141}
5142
5143
5144void KMComposeWin::editorFocusChanged(bool gained)
5145{
5146 mPasteQuotation->setEnabled(gained);
5147}
5148
5149void KMComposeWin::slotSetAlwaysSend( bool bAlways )
5150{
5151 mAlwaysSend = bAlways;
5152}
5153
5154void KMComposeWin::slotListAction( const TQString& style )
5155{
5156 toggleMarkup(true);
5157 if ( style == i18n( "Standard" ) )
5158 mEditor->setParagType( TQStyleSheetItem::DisplayBlock, TQStyleSheetItem::ListDisc );
5159 else if ( style == i18n( "Bulleted List (Disc)" ) )
5160 mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDisc );
5161 else if ( style == i18n( "Bulleted List (Circle)" ) )
5162 mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListCircle );
5163 else if ( style == i18n( "Bulleted List (Square)" ) )
5164 mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListSquare );
5165 else if ( style == i18n( "Ordered List (Decimal)" ))
5166 mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDecimal );
5167 else if ( style == i18n( "Ordered List (Alpha lower)" ) )
5168 mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListLowerAlpha );
5169 else if ( style == i18n( "Ordered List (Alpha upper)" ) )
5170 mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListUpperAlpha );
5171 mEditor->viewport()->setFocus();
5172}
5173
5174void KMComposeWin::slotFontAction( const TQString& font)
5175{
5176 toggleMarkup(true);
5177 mEditor->TQTextEdit::setFamily( font );
5178 mEditor->viewport()->setFocus();
5179}
5180
5181void KMComposeWin::slotSizeAction( int size )
5182{
5183 toggleMarkup(true);
5184 mEditor->setPointSize( size );
5185 mEditor->viewport()->setFocus();
5186}
5187
5188void KMComposeWin::slotAlignLeft()
5189{
5190 toggleMarkup(true);
5191 mEditor->TQTextEdit::setAlignment( AlignLeft );
5192}
5193
5194void KMComposeWin::slotAlignCenter()
5195{
5196 toggleMarkup(true);
5197 mEditor->TQTextEdit::setAlignment( AlignHCenter );
5198}
5199
5200void KMComposeWin::slotAlignRight()
5201{
5202 toggleMarkup(true);
5203 mEditor->TQTextEdit::setAlignment( AlignRight );
5204}
5205
5206void KMComposeWin::slotTextBold()
5207{
5208 toggleMarkup(true);
5209 mEditor->TQTextEdit::setBold( textBoldAction->isChecked() );
5210}
5211
5212void KMComposeWin::slotTextItalic()
5213{
5214 toggleMarkup(true);
5215 mEditor->TQTextEdit::setItalic( textItalicAction->isChecked() );
5216}
5217
5218void KMComposeWin::slotTextUnder()
5219{
5220 toggleMarkup(true);
5221 mEditor->TQTextEdit::setUnderline( textUnderAction->isChecked() );
5222}
5223
5224void KMComposeWin::slotFormatReset()
5225{
5226 mEditor->setColor(mForeColor);
5227 mEditor->setCurrentFont( mSaveFont ); // fontChanged is called now
5228}
5229void KMComposeWin::slotTextColor()
5230{
5231 TQColor color = mEditor->color();
5232
5233 if ( KColorDialog::getColor( color, this ) ) {
5234 toggleMarkup(true);
5235 mEditor->setColor( color );
5236 }
5237}
5238
5239void KMComposeWin::fontChanged( const TQFont &f )
5240{
5241 TQFont fontTemp = f;
5242 fontTemp.setBold( true );
5243 fontTemp.setItalic( true );
5244 TQFontInfo fontInfo( fontTemp );
5245
5246 if ( fontInfo.bold() ) {
5247 textBoldAction->setChecked( f.bold() );
5248 textBoldAction->setEnabled( true ) ;
5249 } else {
5250 textBoldAction->setEnabled( false );
5251 }
5252
5253 if ( fontInfo.italic() ) {
5254 textItalicAction->setChecked( f.italic() );
5255 textItalicAction->setEnabled( true ) ;
5256 } else {
5257 textItalicAction->setEnabled( false );
5258 }
5259
5260 textUnderAction->setChecked( f.underline() );
5261
5262 fontAction->setFont( f.family() );
5263 fontSizeAction->setFontSize( f.pointSize() );
5264}
5265
5266void KMComposeWin::alignmentChanged( int a )
5267{
5268 //toggleMarkup();
5269 alignLeftAction->setChecked( ( a == AlignAuto ) || ( a & AlignLeft ) );
5270 alignCenterAction->setChecked( ( a & AlignHCenter ) );
5271 alignRightAction->setChecked( ( a & AlignRight ) );
5272}
5273
5274namespace {
5275 class TDEToggleActionResetter {
5276 TDEToggleAction * mAction;
5277 bool mOn;
5278 public:
5279 TDEToggleActionResetter( TDEToggleAction * action, bool on )
5280 : mAction( action ), mOn( on ) {}
5281 ~TDEToggleActionResetter() {
5282 if ( mAction )
5283 mAction->setChecked( mOn );
5284 }
5285 void disable() { mAction = 0; }
5286 };
5287}
5288
5289void KMComposeWin::slotEncryptChiasmusToggled( bool on ) {
5290 mEncryptWithChiasmus = false;
5291
5292 if ( !on )
5293 return;
5294
5295 TDEToggleActionResetter resetter( mEncryptChiasmusAction, false );
5296
5297 const Kleo::CryptoBackend::Protocol * chiasmus =
5298 Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
5299
5300 if ( !chiasmus ) {
5301 const TQString msg = Kleo::CryptoBackendFactory::instance()->knowsAboutProtocol( "Chiasmus" )
5302 ? i18n( "Please configure a Crypto Backend to use for "
5303 "Chiasmus encryption first.\n"
5304 "You can do this in the Crypto Backends tab of "
5305 "the configure dialog's Security page." )
5306 : i18n( "It looks as though libkleopatra was compiled without "
5307 "Chiasmus support. You might want to recompile "
5308 "libkleopatra with --enable-chiasmus.");
5309 KMessageBox::information( this, msg, i18n("No Chiasmus Backend Configured" ) );
5310 return;
5311 }
5312
5313 STD_NAMESPACE_PREFIX unique_ptr<Kleo::SpecialJob> job( chiasmus->specialJob( "x-obtain-keys", TQStringVariantMap() ) );
5314 if ( !job ) {
5315 const TQString msg = i18n( "Chiasmus backend does not offer the "
5316 "\"x-obtain-keys\" function. Please report this bug." );
5317 KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
5318 return;
5319 }
5320
5321 if ( job->exec() ) {
5322 job->showErrorDialog( this, i18n( "Chiasmus Backend Error" ) );
5323 return;
5324 }
5325
5326 const TQVariant result = job->property( "result" );
5327 if ( result.type() != TQVariant::StringList ) {
5328 const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
5329 "The \"x-obtain-keys\" function did not return a "
5330 "string list. Please report this bug." );
5331 KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
5332 return;
5333 }
5334
5335 const TQStringList keys = result.toStringList();
5336 if ( keys.empty() ) {
5337 const TQString msg = i18n( "No keys have been found. Please check that a "
5338 "valid key path has been set in the Chiasmus "
5339 "configuration." );
5340 KMessageBox::information( this, msg, i18n( "No Chiasmus Keys Found" ) );
5341 return;
5342 }
5343
5344 ChiasmusKeySelector selectorDlg( this, i18n( "Chiasmus Encryption Key Selection" ),
5345 keys, GlobalSettings::chiasmusKey(),
5346 GlobalSettings::chiasmusOptions() );
5347 if ( selectorDlg.exec() != TQDialog::Accepted )
5348 return;
5349
5350 GlobalSettings::setChiasmusOptions( selectorDlg.options() );
5351 GlobalSettings::setChiasmusKey( selectorDlg.key() );
5352 assert( !GlobalSettings::chiasmusKey().isEmpty() );
5353 mEncryptWithChiasmus = true;
5354 resetter.disable();
5355}
5356
5357void KMComposeWin::slotEditDone(KMail::EditorWatcher * watcher)
5358{
5359 kdDebug(5006) << k_funcinfo << endl;
5360 KMMessagePart *part = mEditorMap[ watcher ];
5361 KTempFile *tf = mEditorTempFiles[ watcher ];
5362 mEditorMap.remove( watcher );
5363 mEditorTempFiles.remove( watcher );
5364 if ( !watcher->fileChanged() )
5365 return;
5366
5367 tf->file()->reset();
5368 TQByteArray data = tf->file()->readAll();
5369 part->setBodyEncodedBinary( data );
5370}
5371
5372
5373void KMComposeWin::slotUpdateSignatureAndEncrypionStateIndicators()
5374{
5375 const bool showIndicatorsAlways = false; // FIXME config option?
5376 mSignatureStateIndicator->setText( mSignAction->isChecked()? i18n("Message will be signed") : i18n("Message will not be signed") );
5377 mEncryptionStateIndicator->setText( mEncryptAction->isChecked()? i18n("Message will be encrypted") : i18n("Message will not be encrypted") );
5378 if ( !showIndicatorsAlways ) {
5379 mSignatureStateIndicator->setShown( mSignAction->isChecked() );
5380 mEncryptionStateIndicator->setShown( mEncryptAction->isChecked() );
5381 }
5382}
5383
5384void KMComposeWin::slotAttachmentDragStarted()
5385{
5386 kdDebug(5006) << k_funcinfo << endl;
5387 int idx = 0;
5388 TQStringList filenames;
5389 for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++idx ) {
5390 if ( (*it)->isSelected() ) {
5391 KMMessagePart* msgPart = mAtmList.at(idx);
5392 KTempDir * tempDir = new KTempDir(); // will be deleted on composer close
5393 tempDir->setAutoDelete( true );
5394 mTempDirs.insert( tempDir );
5395 const TQString fileName = tempDir->name() + "/" + msgPart->name();
5396 KPIM::kByteArrayToFile(msgPart->bodyDecodedBinary(),
5397 fileName,
5398 false, false, false);
5399 KURL url;
5400 url.setPath( fileName );
5401 filenames << url.path();
5402 }
5403 }
5404 if ( filenames.isEmpty() ) return;
5405
5406 TQUriDrag *drag = new TQUriDrag( mAtmListView );
5407 drag->setFileNames( filenames );
5408 drag->dragCopy();
5409}
5410
5411void KMComposeWin::recipientEditorSizeHintChanged()
5412{
5413 TQTimer::singleShot( 1, this, TQ_SLOT(setMaximumHeaderSize()) );
5414}
5415
5416void KMComposeWin::setMaximumHeaderSize()
5417{
5418 mHeadersArea->setMaximumHeight( mHeadersArea->sizeHint().height() );
5419}
5420
Provides encoding detection capabilities.
const char * encoding() const
Convenience method.
bool analyze(const char *data, int len)
Analyze text data.
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
Definition: kcursorsaver.h:14
Mail folder.
Definition: kmfolder.h:69
TQString idString() const
Returns a string that can be used to identify this folder.
Definition: kmfolder.cpp:705
KMMsgInfo * unGetMsg(int idx)
Replace KMMessage with KMMsgInfo and delete KMMessage
Definition: kmfolder.cpp:326
int addMsg(KMMessage *msg, int *index_return=0)
Add the given message to the folder.
Definition: kmfolder.cpp:390
void close(const char *owner, bool force=false)
Close folder.
Definition: kmfolder.cpp:489
KMMessage * getMsg(int idx)
Read message at given index.
Definition: kmfolder.cpp:321
int count(bool cache=false) const
Number of messages in this folder.
Definition: kmfolder.cpp:445
int open(const char *owner)
Open folder for access.
Definition: kmfolder.cpp:479
static TQString localDataPath()
Returns the full path of the user's local data directory for KMail.
Definition: kmkernel.cpp:2111
This is a Mime Message.
Definition: kmmessage.h:68
static KPIM::EmailParseResult isValidEmailAddressList(const TQString &aStr, TQString &brokenAddress)
Validate a list of email addresses, and also allow aliases and distribution lists to be expanded befo...
Definition: kmmessage.cpp:273
bool isUrgent() const
Definition: kmmessage.cpp:259
static TQString smartQuote(const TQString &msg, int maxLineLength)
Given argument msg add quoting characters and relayout for max width maxLength.
Definition: kmmessage.cpp:646
static const TQStringList & preferredCharsets()
Get a list of preferred message charsets.
Definition: kmmessage.cpp:4092
static TQString expandAliases(const TQString &recipients)
Expands aliases (distribution lists and nick names) and appends a domain part to all email addresses ...
Definition: kmmessage.cpp:3953
const DwString & asDwString() const
Return the entire message contents in the DwString.
Definition: kmmessage.cpp:292
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
Definition: kmmessage.cpp:2289
static TQCString defaultCharset()
Get the default message charset.
Definition: kmmessage.cpp:4075
TQString fcc() const
Get or set the 'Fcc' header field.
Definition: kmmessage.cpp:1981
void initHeader(uint identity=0)
Initialize header fields.
Definition: kmmessage.cpp:1715
The attachment dialog with convenience backward compatible methods.
Definition: kmmsgpartdlg.h:141
A combo box for selecting the dictionary used for spell checking.
Starts an editor for the given URL and emits an signal when editing has been finished.
Definition: editorwatcher.h:39
static TQStringList transportNames()
Returns the list for transport names.
DCOP interface for mail composer window.
This is the widget which gets added to the right TreeToolView.
Definition: snippetwidget.h:46
folderdiaquotatab.h
Definition: aboutdata.cpp:40