kmail

kmcommands.cpp
1/*
2 This file is part of KMail, the KDE mail client.
3 Copyright (c) 2002 Don Sanders <sanders@kde.org>
4
5 KMail is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License, version 2, as
7 published by the Free Software Foundation.
8
9 KMail is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19//
20// This file implements various "command" classes. These command classes
21// are based on the command design pattern.
22//
23// Historically various operations were implemented as slots of KMMainWin.
24// This proved inadequate as KMail has multiple top level windows
25// (KMMainWin, KMReaderMainWin, SearchWindow, KMComposeWin) that may
26// benefit from using these operations. It is desirable that these
27// classes can operate without depending on or altering the state of
28// a KMMainWin, in fact it is possible no KMMainWin object even exists.
29//
30// Now these operations have been rewritten as KMCommand based classes,
31// making them independent of KMMainWin.
32//
33// The base command class KMCommand is async, which is a difference
34// from the conventional command pattern. As normal derived classes implement
35// the execute method, but client classes call start() instead of
36// calling execute() directly. start() initiates async operations,
37// and on completion of these operations calls execute() and then deletes
38// the command. (So the client must not construct commands on the stack).
39//
40// The type of async operation supported by KMCommand is retrieval
41// of messages from an IMAP server.
42
43#include "kmcommands.h"
44
45#ifdef HAVE_CONFIG_H
46#include <config.h>
47#endif
48
49#include <errno.h>
50#include <mimelib/enum.h>
51#include <mimelib/field.h>
52#include <mimelib/mimepp.h>
53#include <mimelib/string.h>
54#include <tdeapplication.h>
55#include <dcopclient.h>
56
57#include <tqtextcodec.h>
58#include <tqpopupmenu.h>
59#include <tqeventloop.h>
60
61#include <libemailfunctions/email.h>
62#include <kdcopservicestarter.h>
63#include <kdebug.h>
64#include <tdefiledialog.h>
65#include <tdeabc/stdaddressbook.h>
66#include <tdeabc/addresseelist.h>
67#include <kdirselectdialog.h>
68#include <tdelocale.h>
69#include <tdemessagebox.h>
70#include <tdeparts/browserextension.h>
71#include <kprogress.h>
72#include <krun.h>
73#include <kbookmarkmanager.h>
74#include <tdestandarddirs.h>
75#include <tdetempfile.h>
76#include <tdeimproxy.h>
77#include <kuserprofile.h>
78// TDEIO headers
79#include <tdeio/job.h>
80#include <tdeio/netaccess.h>
81
82#include <libkpimidentities/identitymanager.h>
83
84#include "actionscheduler.h"
85using KMail::ActionScheduler;
86#include "mailinglist-magic.h"
87#include "kmaddrbook.h"
88#include <kaddrbook.h>
89#include "composer.h"
90#include "kmfiltermgr.h"
91#include "kmfoldermbox.h"
92#include "kmfolderimap.h"
93#include "kmfoldermgr.h"
94#include "kmheaders.h"
95#include "headeritem.h"
96#include "kmmainwidget.h"
97#include "kmmsgdict.h"
98#include "messagesender.h"
99#include "kmmsgpartdlg.h"
100#include "undostack.h"
101#include "kcursorsaver.h"
102#include "partNode.h"
103#include "objecttreeparser.h"
104#include "csshelper.h"
105using KMail::ObjectTreeParser;
106using KMail::FolderJob;
107#include "chiasmuskeyselector.h"
108#include "mailsourceviewer.h"
109using KMail::MailSourceViewer;
110#include "kmreadermainwin.h"
111#include "secondarywindow.h"
113#include "redirectdialog.h"
115#include "util.h"
116#include "templateparser.h"
117#include "editorwatcher.h"
118#include "korghelper.h"
119
120#include "broadcaststatus.h"
121#include "globalsettings.h"
122
123#include <libtdepim/tdefileio.h>
124#include "kcalendariface_stub.h"
125
126#include "progressmanager.h"
127using KPIM::ProgressManager;
128using KPIM::ProgressItem;
129#include <kmime_mdn.h>
130using namespace KMime;
131
132#include <kleo/specialjob.h>
133#include <kleo/cryptobackend.h>
134#include <kleo/cryptobackendfactory.h>
135
136#include <tqclipboard.h>
137
138#include <memory>
139
140class LaterDeleterWithCommandCompletion : public KMail::Util::LaterDeleter
141{
142public:
143 LaterDeleterWithCommandCompletion( KMCommand* command )
144 :LaterDeleter( command ), m_result( KMCommand::Failed )
145 {
146 }
147 ~LaterDeleterWithCommandCompletion()
148 {
149 setResult( m_result );
150 KMCommand *command = static_cast<KMCommand*>( m_object );
151 emit command->completed( command );
152 }
153 void setResult( KMCommand::Result v ) { m_result = v; }
154private:
155 KMCommand::Result m_result;
156};
157
158
159KMCommand::KMCommand( TQWidget *parent )
160 : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
161 mEmitsCompletedItself( false ), mParent( parent )
162{
163}
164
165KMCommand::KMCommand( TQWidget *parent, const TQPtrList<KMMsgBase> &msgList )
166 : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
167 mEmitsCompletedItself( false ), mParent( parent ), mMsgList( msgList )
168{
169}
170
171KMCommand::KMCommand( TQWidget *parent, KMMsgBase *msgBase )
172 : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
173 mEmitsCompletedItself( false ), mParent( parent )
174{
175 mMsgList.append( msgBase );
176}
177
178KMCommand::KMCommand( TQWidget *parent, KMMessage *msg )
179 : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
180 mEmitsCompletedItself( false ), mParent( parent )
181{
182 if (msg)
183 mMsgList.append( &msg->toMsgBase() );
184}
185
186KMCommand::~KMCommand()
187{
188 TQValueListIterator<TQGuardedPtr<KMFolder> > fit;
189 for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
190 if (!(*fit))
191 continue;
192 (*fit)->close("kmcommand");
193 }
194}
195
196KMCommand::Result KMCommand::result()
197{
198 if ( mResult == Undefined )
199 kdDebug(5006) << k_funcinfo << "mResult is Undefined" << endl;
200 return mResult;
201}
202
203void KMCommand::start()
204{
205 TQTimer::singleShot( 0, this, TQ_SLOT( slotStart() ) );
206}
207
208
209const TQPtrList<KMMessage> KMCommand::retrievedMsgs() const
210{
211 return mRetrievedMsgs;
212}
213
214KMMessage *KMCommand::retrievedMessage() const
215{
216 return mRetrievedMsgs.getFirst();
217}
218
219TQWidget *KMCommand::parentWidget() const
220{
221 return mParent;
222}
223
224int KMCommand::mCountJobs = 0;
225
226void KMCommand::slotStart()
227{
228 connect( this, TQ_SIGNAL( messagesTransfered( KMCommand::Result ) ),
229 this, TQ_SLOT( slotPostTransfer( KMCommand::Result ) ) );
230 kmkernel->filterMgr()->ref();
231
232 if (mMsgList.find(0) != -1) {
233 emit messagesTransfered( Failed );
234 return;
235 }
236
237 if ((mMsgList.count() == 1) &&
238 (mMsgList.getFirst()->isMessage()) &&
239 (mMsgList.getFirst()->parent() == 0))
240 {
241 // Special case of operating on message that isn't in a folder
242 mRetrievedMsgs.append((KMMessage*)mMsgList.getFirst());
243 emit messagesTransfered( OK );
244 return;
245 }
246
247 for ( KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next() ) {
248 if ( mb ) {
249 if ( !mb->parent() ) {
250 emit messagesTransfered( Failed );
251 return;
252 } else {
253 keepFolderOpen( mb->parent() );
254 }
255 }
256 }
257
258 // transfer the selected messages first
259 transferSelectedMsgs();
260}
261
262void KMCommand::slotPostTransfer( KMCommand::Result result )
263{
264 disconnect( this, TQ_SIGNAL( messagesTransfered( KMCommand::Result ) ),
265 this, TQ_SLOT( slotPostTransfer( KMCommand::Result ) ) );
266 if ( result == OK )
267 result = execute();
268 mResult = result;
269 TQPtrListIterator<KMMessage> it( mRetrievedMsgs );
270 KMMessage* msg;
271 while ( (msg = it.current()) != 0 )
272 {
273 ++it;
274 if (msg->parent())
275 msg->setTransferInProgress(false);
276 }
277 kmkernel->filterMgr()->deref();
278 if ( !emitsCompletedItself() )
279 emit completed( this );
280 if ( !deletesItself() )
281 deleteLater();
282}
283
284void KMCommand::transferSelectedMsgs()
285{
286 // make sure no other transfer is active
287 if (KMCommand::mCountJobs > 0) {
288 emit messagesTransfered( Failed );
289 return;
290 }
291
292 bool complete = true;
293 KMCommand::mCountJobs = 0;
294 mCountMsgs = 0;
295 mRetrievedMsgs.clear();
296 mCountMsgs = mMsgList.count();
297 uint totalSize = 0;
298 // the KProgressDialog for the user-feedback. Only enable it if it's needed.
299 // For some commands like KMSeStatusCommand it's not needed. Note, that
300 // for some reason the KProgressDialog eats the MouseReleaseEvent (if a
301 // command is executed after the MousePressEvent), cf. bug #71761.
302 if ( mCountMsgs > 0 ) {
303 mProgressDialog = new KProgressDialog(mParent, "transferProgress",
304 i18n("Please wait"),
305 i18n("Please wait while the message is transferred",
306 "Please wait while the %n messages are transferred", mMsgList.count()),
307 true);
308 mProgressDialog->setMinimumDuration(1000);
309 }
310 for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
311 {
312 // check if all messages are complete
313 KMMessage *thisMsg = 0;
314 if ( mb->isMessage() )
315 thisMsg = static_cast<KMMessage*>(mb);
316 else
317 {
318 KMFolder *folder = mb->parent();
319 int idx = folder->find(mb);
320 if (idx < 0) continue;
321 thisMsg = folder->getMsg(idx);
322 }
323 if (!thisMsg) continue;
324 if ( thisMsg->transferInProgress() &&
325 thisMsg->parent()->folderType() == KMFolderTypeImap )
326 {
327 thisMsg->setTransferInProgress( false, true );
328 thisMsg->parent()->ignoreJobsForMessage( thisMsg );
329 }
330
331 if ( thisMsg->parent() && !thisMsg->isComplete() &&
332 ( !mProgressDialog || !mProgressDialog->wasCancelled() ) )
333 {
334 kdDebug(5006)<<"### INCOMPLETE\n";
335 // the message needs to be transferred first
336 complete = false;
337 KMCommand::mCountJobs++;
338 FolderJob *job = thisMsg->parent()->createJob(thisMsg);
339 job->setCancellable( false );
340 totalSize += thisMsg->msgSizeServer();
341 // emitted when the message was transferred successfully
342 connect(job, TQ_SIGNAL(messageRetrieved(KMMessage*)),
343 this, TQ_SLOT(slotMsgTransfered(KMMessage*)));
344 // emitted when the job is destroyed
345 connect(job, TQ_SIGNAL(finished()),
346 this, TQ_SLOT(slotJobFinished()));
347 connect(job, TQ_SIGNAL(progress(unsigned long, unsigned long)),
348 this, TQ_SLOT(slotProgress(unsigned long, unsigned long)));
349 // msg musn't be deleted
350 thisMsg->setTransferInProgress(true);
351 job->start();
352 } else {
353 thisMsg->setTransferInProgress(true);
354 mRetrievedMsgs.append(thisMsg);
355 }
356 }
357
358 if (complete)
359 {
360 delete mProgressDialog;
361 mProgressDialog = 0;
362 emit messagesTransfered( OK );
363 } else {
364 // wait for the transfer and tell the progressBar the necessary steps
365 if ( mProgressDialog ) {
366 connect(mProgressDialog, TQ_SIGNAL(cancelClicked()),
367 this, TQ_SLOT(slotTransferCancelled()));
368 mProgressDialog->progressBar()->setTotalSteps(totalSize);
369 }
370 }
371}
372
373void KMCommand::slotMsgTransfered(KMMessage* msg)
374{
375 if ( mProgressDialog && mProgressDialog->wasCancelled() ) {
376 emit messagesTransfered( Canceled );
377 return;
378 }
379
380 // save the complete messages
381 mRetrievedMsgs.append(msg);
382}
383
384void KMCommand::slotProgress( unsigned long done, unsigned long /*total*/ )
385{
386 mProgressDialog->progressBar()->setProgress( done );
387}
388
389void KMCommand::slotJobFinished()
390{
391 // the job is finished (with / without error)
392 KMCommand::mCountJobs--;
393
394 if ( mProgressDialog && mProgressDialog->wasCancelled() ) return;
395
396 if ( (mCountMsgs - static_cast<int>(mRetrievedMsgs.count())) > KMCommand::mCountJobs )
397 {
398 // the message wasn't retrieved before => error
399 if ( mProgressDialog )
400 mProgressDialog->hide();
401 slotTransferCancelled();
402 return;
403 }
404 // update the progressbar
405 if ( mProgressDialog ) {
406 mProgressDialog->setLabel(i18n("Please wait while the message is transferred",
407 "Please wait while the %n messages are transferred", KMCommand::mCountJobs));
408 }
409 if (KMCommand::mCountJobs == 0)
410 {
411 // all done
412 delete mProgressDialog;
413 mProgressDialog = 0;
414 emit messagesTransfered( OK );
415 }
416}
417
418void KMCommand::slotTransferCancelled()
419{
420 // kill the pending jobs
421 TQValueListIterator<TQGuardedPtr<KMFolder> > fit;
422 for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
423 if (!(*fit))
424 continue;
425 KMFolder *folder = *fit;
426 KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder);
427 if (imapFolder && imapFolder->account()) {
428 imapFolder->account()->killAllJobs();
429 }
430 }
431
432 KMCommand::mCountJobs = 0;
433 mCountMsgs = 0;
434 // unget the transfered messages
435 TQPtrListIterator<KMMessage> it( mRetrievedMsgs );
436 KMMessage* msg;
437 while ( (msg = it.current()) != 0 )
438 {
439 KMFolder *folder = msg->parent();
440 ++it;
441 if (!folder)
442 continue;
443 msg->setTransferInProgress(false);
444 int idx = folder->find(msg);
445 if (idx > 0) folder->unGetMsg(idx);
446 }
447 mRetrievedMsgs.clear();
448 emit messagesTransfered( Canceled );
449}
450
451void KMCommand::keepFolderOpen( KMFolder *folder )
452{
453 folder->open( "kmcommand" );
454 mFolders.append( folder );
455}
456
457KMMailtoComposeCommand::KMMailtoComposeCommand( const KURL &url,
458 KMMessage *msg )
459 :mUrl( url ), mMessage( msg )
460{
461}
462
463KMCommand::Result KMMailtoComposeCommand::execute()
464{
465 KMMessage *msg = new KMMessage;
466 uint id = 0;
467
468 if ( mMessage && mMessage->parent() )
469 id = mMessage->parent()->identity();
470
471 msg->initHeader(id);
472 msg->setCharset("utf-8");
473 msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
474
475 KMail::Composer * win = KMail::makeComposer( msg, id );
476 win->setCharset("", true);
477 win->setFocusToSubject();
478 win->show();
479
480 return OK;
481}
482
483
484KMMailtoReplyCommand::KMMailtoReplyCommand( TQWidget *parent,
485 const KURL &url, KMMessage *msg, const TQString &selection )
486 :KMCommand( parent, msg ), mUrl( url ), mSelection( selection )
487{
488}
489
490KMCommand::Result KMMailtoReplyCommand::execute()
491{
492 //TODO : consider factoring createReply into this method.
493 KMMessage *msg = retrievedMessage();
494 if ( !msg || !msg->codec() ) {
495 return Failed;
496 }
497 KMMessage *rmsg = msg->createReply( KMail::ReplyNone, mSelection );
498 rmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
499
500 KMail::Composer * win = KMail::makeComposer( rmsg, 0 );
501 win->setCharset(msg->codec()->mimeName(), true);
502 win->setReplyFocus();
503 win->show();
504
505 return OK;
506}
507
508
509KMMailtoForwardCommand::KMMailtoForwardCommand( TQWidget *parent,
510 const KURL &url, KMMessage *msg )
511 :KMCommand( parent, msg ), mUrl( url )
512{
513}
514
515KMCommand::Result KMMailtoForwardCommand::execute()
516{
517 //TODO : consider factoring createForward into this method.
518 KMMessage *msg = retrievedMessage();
519 if ( !msg || !msg->codec() ) {
520 return Failed;
521 }
522 KMMessage *fmsg = msg->createForward();
523 fmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
524
525 KMail::Composer * win = KMail::makeComposer( fmsg );
526 win->setCharset(msg->codec()->mimeName(), true);
527 win->show();
528
529 return OK;
530}
531
532
533KMAddBookmarksCommand::KMAddBookmarksCommand( const KURL &url, TQWidget *parent )
534 : KMCommand( parent ), mUrl( url )
535{
536}
537
538KMCommand::Result KMAddBookmarksCommand::execute()
539{
540 TQString filename = locateLocal( "data", TQString::fromLatin1("konqueror/bookmarks.xml") );
541 KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename,
542 false );
543 KBookmarkGroup group = bookManager->root();
544 group.addBookmark( bookManager, mUrl.path(), KURL( mUrl ) );
545 if( bookManager->save() ) {
546 bookManager->emitChanged( group );
547 }
548
549 return OK;
550}
551
552KMMailtoAddAddrBookCommand::KMMailtoAddAddrBookCommand( const KURL &url,
553 TQWidget *parent )
554 : KMCommand( parent ), mUrl( url )
555{
556}
557
558KMCommand::Result KMMailtoAddAddrBookCommand::execute()
559{
560 KAddrBookExternal::addEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
561 parentWidget() );
562
563 return OK;
564}
565
566
567KMMailtoOpenAddrBookCommand::KMMailtoOpenAddrBookCommand( const KURL &url,
568 TQWidget *parent )
569 : KMCommand( parent ), mUrl( url )
570{
571}
572
573KMCommand::Result KMMailtoOpenAddrBookCommand::execute()
574{
575 KAddrBookExternal::openEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
576 parentWidget() );
577
578 return OK;
579}
580
581
582KMUrlCopyCommand::KMUrlCopyCommand( const KURL &url, KMMainWidget *mainWidget )
583 :mUrl( url ), mMainWidget( mainWidget )
584{
585}
586
587KMCommand::Result KMUrlCopyCommand::execute()
588{
589 TQClipboard* clip = TQApplication::clipboard();
590
591 if (mUrl.protocol() == "mailto") {
592 // put the url into the mouse selection and the clipboard
593 TQString address = KMMessage::decodeMailtoUrl( mUrl.path() );
594 clip->setSelectionMode( true );
595 clip->setText( address );
596 clip->setSelectionMode( false );
597 clip->setText( address );
598 KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "Address copied to clipboard." ));
599 } else {
600 // put the url into the mouse selection and the clipboard
601 clip->setSelectionMode( true );
602 clip->setText( mUrl.url() );
603 clip->setSelectionMode( false );
604 clip->setText( mUrl.url() );
605 KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "URL copied to clipboard." ));
606 }
607
608 return OK;
609}
610
611
612KMUrlOpenCommand::KMUrlOpenCommand( const KURL &url, KMReaderWin *readerWin )
613 :mUrl( url ), mReaderWin( readerWin )
614{
615}
616
617KMCommand::Result KMUrlOpenCommand::execute()
618{
619 if ( !mUrl.isEmpty() )
620 mReaderWin->slotUrlOpen( mUrl, KParts::URLArgs() );
621
622 return OK;
623}
624
625
626KMUrlSaveCommand::KMUrlSaveCommand( const KURL &url, TQWidget *parent )
627 : KMCommand( parent ), mUrl( url )
628{
629}
630
631KMCommand::Result KMUrlSaveCommand::execute()
632{
633 if ( mUrl.isEmpty() )
634 return OK;
635 KURL saveUrl = KFileDialog::getSaveURL(mUrl.fileName(), TQString(),
636 parentWidget() );
637 if ( saveUrl.isEmpty() )
638 return Canceled;
639 if ( TDEIO::NetAccess::exists( saveUrl, false, parentWidget() ) )
640 {
641 if (KMessageBox::warningContinueCancel(0,
642 i18n("<qt>File <b>%1</b> exists.<br>Do you want to replace it?</qt>")
643 .arg(saveUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
644 != KMessageBox::Continue)
645 return Canceled;
646 }
647 TDEIO::Job *job = TDEIO::file_copy(mUrl, saveUrl, -1, true);
648 connect(job, TQ_SIGNAL(result(TDEIO::Job*)), TQ_SLOT(slotUrlSaveResult(TDEIO::Job*)));
649 setEmitsCompletedItself( true );
650 return OK;
651}
652
653void KMUrlSaveCommand::slotUrlSaveResult( TDEIO::Job *job )
654{
655 if ( job->error() ) {
656 job->showErrorDialog();
657 setResult( Failed );
658 emit completed( this );
659 }
660 else {
661 setResult( OK );
662 emit completed( this );
663 }
664}
665
666
667KMEditMsgCommand::KMEditMsgCommand( TQWidget *parent, KMMessage *msg )
668 :KMCommand( parent, msg )
669{
670}
671
672KMCommand::Result KMEditMsgCommand::execute()
673{
674 KMMessage *msg = retrievedMessage();
675 if ( !msg || !msg->parent() ||
676 ( !kmkernel->folderIsDraftOrOutbox( msg->parent() ) &&
677 !kmkernel->folderIsTemplates( msg->parent() ) ) )
678 return Failed;
679
680 // Remember the old parent, we need it a bit further down to be able
681 // to put the unchanged messsage back in the original folder if the nth
682 // edit is discarded, for n > 1.
683 KMFolder *parent = msg->parent();
684 if ( parent )
685 parent->take( parent->find( msg ) );
686
687 KMail::Composer * win = KMail::makeComposer();
688 msg->setTransferInProgress(false); // From here on on, the composer owns the message.
689 win->setMsg(msg, false, true);
690 win->setFolder( parent );
691 win->show();
692
693 return OK;
694}
695
696KMUseTemplateCommand::KMUseTemplateCommand( TQWidget *parent, KMMessage *msg )
697 :KMCommand( parent, msg )
698{
699}
700
701KMCommand::Result KMUseTemplateCommand::execute()
702{
703 KMMessage *msg = retrievedMessage();
704 if ( !msg || !msg->parent() ||
705 !kmkernel->folderIsTemplates( msg->parent() ) )
706 return Failed;
707
708 // Take a copy of the original message, which remains unchanged.
709 KMMessage *newMsg = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
710 newMsg->setComplete( msg->isComplete() );
711
712 // these fields need to be regenerated for the new message
713 newMsg->removeHeaderField("Date");
714 newMsg->removeHeaderField("Message-ID");
715
716 KMail::Composer *win = KMail::makeComposer();
717 newMsg->setTransferInProgress( false ); // From here on on, the composer owns the message.
718 win->setMsg( newMsg, false, true );
719 win->show();
720
721 return OK;
722}
723
724KMShowMsgSrcCommand::KMShowMsgSrcCommand( TQWidget *parent,
725 KMMessage *msg, bool fixedFont )
726 :KMCommand( parent, msg ), mFixedFont( fixedFont )
727{
728 // remember complete state
729 mMsgWasComplete = msg->isComplete();
730}
731
732KMCommand::Result KMShowMsgSrcCommand::execute()
733{
734 KMMessage *msg = retrievedMessage();
735 if ( !msg || !msg->codec() ) {
736 return Failed;
737 }
738 if ( msg->isComplete() && !mMsgWasComplete )
739 msg->notify(); // notify observers as msg was transfered
740 TQString str = msg->codec()->toUnicode( msg->asString() );
741
742 MailSourceViewer *viewer = new MailSourceViewer(); // deletes itself upon close
743 viewer->setCaption( i18n("Message as Plain Text") );
744 viewer->setText(str);
745 if( mFixedFont )
746 viewer->setFont(TDEGlobalSettings::fixedFont());
747
748 // Well, there is no widget to be seen here, so we have to use TQCursor::pos()
749 // Update: (GS) I'm not going to make this code behave according to Xinerama
750 // configuration because this is quite the hack.
751 if (TQApplication::desktop()->isVirtualDesktop()) {
752 int scnum = TQApplication::desktop()->screenNumber(TQCursor::pos());
753 viewer->resize(TQApplication::desktop()->screenGeometry(scnum).width()/2,
754 2*TQApplication::desktop()->screenGeometry(scnum).height()/3);
755 } else {
756 viewer->resize(TQApplication::desktop()->geometry().width()/2,
757 2*TQApplication::desktop()->geometry().height()/3);
758 }
759 viewer->show();
760
761 return OK;
762}
763
764static KURL subjectToUrl( const TQString & subject )
765{
766 // We need to replace colons with underscores since those cause problems with KFileDialog (bug
767 // in KFileDialog though) and also on Windows filesystems.
768 // We also look at the special case of ": ", since converting that to "_ " would look strange,
769 // simply "_" looks better.
770 // We also don't allow filenames starting with a dot, since then the file is hidden and the poor
771 // user can't find it anymore.
772 // Don't allow filenames starting with a tilde either, since that will cause the file dialog to
773 // discard the filename entirely.
774 // https://issues.kolab.org/issue3805
775 const TQString filter = i18n( "*.mbox|email messages (*.mbox)\n*|all files (*)" );
776 TQString cleanSubject = subject.stripWhiteSpace()
777 .replace( TQDir::separator(), '_' )
778 .replace( ": ", "_" )
779 .replace( ':', '_' )
780 .replace( '.', '_' )
781 .replace( '~', '_' );
782 return KFileDialog::getSaveURL( cleanSubject, filter );
783}
784
785KMSaveMsgCommand::KMSaveMsgCommand( TQWidget *parent, KMMessage * msg )
786 : KMCommand( parent ),
787 mMsgListIndex( 0 ),
788 mStandAloneMessage( 0 ),
789 mOffset( 0 ),
790 mTotalSize( msg ? msg->msgSize() : 0 )
791{
792 if ( !msg ) return;
793 setDeletesItself( true );
794 // If the mail has a serial number, operate on sernums, if it does not
795 // we need to work with the pointer, but can be reasonably sure it won't
796 // go away, since it'll be an encapsulated message or one that was opened
797 // from an .eml file.
798 if ( msg->getMsgSerNum() != 0 ) {
799 mMsgList.append( msg->getMsgSerNum() );
800 if ( msg->parent() ) {
801 msg->parent()->open( "kmsavemsgcommand" );
802 }
803 } else {
804 mStandAloneMessage = msg;
805 }
806 mUrl = subjectToUrl( msg->cleanSubject() );
807}
808
809KMSaveMsgCommand::KMSaveMsgCommand( TQWidget *parent,
810 const TQPtrList<KMMsgBase> &msgList )
811 : KMCommand( parent ),
812 mMsgListIndex( 0 ),
813 mStandAloneMessage( 0 ),
814 mOffset( 0 ),
815 mTotalSize( 0 )
816{
817 if (!msgList.getFirst())
818 return;
819 setDeletesItself( true );
820 KMMsgBase *msgBase = msgList.getFirst();
821
822 // We operate on serNums and not the KMMsgBase pointers, as those can
823 // change, or become invalid when changing the current message, switching
824 // folders, etc.
825 TQPtrListIterator<KMMsgBase> it(msgList);
826 while ( it.current() ) {
827 mMsgList.append( (*it)->getMsgSerNum() );
828 mTotalSize += (*it)->msgSize();
829 if ((*it)->parent() != 0)
830 (*it)->parent()->open("kmcommand");
831 ++it;
832 }
833 mMsgListIndex = 0;
834 mUrl = subjectToUrl( msgBase->cleanSubject() );
835}
836
837KURL KMSaveMsgCommand::url()
838{
839 return mUrl;
840}
841
842KMCommand::Result KMSaveMsgCommand::execute()
843{
844 mJob = TDEIO::put( mUrl, S_IRUSR|S_IWUSR, false, false );
845 mJob->slotTotalSize( mTotalSize );
846 mJob->setAsyncDataEnabled( true );
847 mJob->setReportDataSent( true );
848 connect(mJob, TQ_SIGNAL(dataReq(TDEIO::Job*, TQByteArray &)),
849 TQ_SLOT(slotSaveDataReq()));
850 connect(mJob, TQ_SIGNAL(result(TDEIO::Job*)),
851 TQ_SLOT(slotSaveResult(TDEIO::Job*)));
852 setEmitsCompletedItself( true );
853 return OK;
854}
855
856void KMSaveMsgCommand::slotSaveDataReq()
857{
858 int remainingBytes = mData.size() - mOffset;
859 if ( remainingBytes > 0 ) {
860 // eat leftovers first
861 if ( remainingBytes > MAX_CHUNK_SIZE )
862 remainingBytes = MAX_CHUNK_SIZE;
863
864 TQByteArray data;
865 data.duplicate( mData.data() + mOffset, remainingBytes );
866 mJob->sendAsyncData( data );
867 mOffset += remainingBytes;
868 return;
869 }
870 // No leftovers, process next message.
871 if ( mMsgListIndex < mMsgList.size() ) {
872 KMMessage *msg = 0;
873 int idx = -1;
874 KMFolder * p = 0;
875 KMMsgDict::instance()->getLocation( mMsgList[mMsgListIndex], &p, &idx );
876 assert( p );
877 assert( idx >= 0 );
878 //kdDebug() << "SERNUM: " << mMsgList[mMsgListIndex] << " idx: " << idx << " folder: " << p->prettyURL() << endl;
879
880 const bool alreadyGot = p->isMessage( idx );
881
882 msg = p->getMsg(idx);
883
884 if ( msg ) {
885 // Only unGet the message if it isn't already got.
886 if ( !alreadyGot ) {
887 mUngetMsgs.append( msg );
888 }
889 if ( msg->transferInProgress() ) {
890 TQByteArray data = TQByteArray();
891 mJob->sendAsyncData( data );
892 }
893 msg->setTransferInProgress( true );
894 if ( msg->isComplete() ) {
895 slotMessageRetrievedForSaving( msg );
896 } else {
897 // retrieve Message first
898 if ( msg->parent() && !msg->isComplete() ) {
899 FolderJob *job = msg->parent()->createJob( msg );
900 job->setCancellable( false );
901 connect(job, TQ_SIGNAL( messageRetrieved( KMMessage* ) ),
902 this, TQ_SLOT( slotMessageRetrievedForSaving( KMMessage* ) ) );
903 job->start();
904 }
905 }
906 } else {
907 mJob->slotError( TDEIO::ERR_ABORTED,
908 i18n("The message was removed while saving it. "
909 "It has not been saved.") );
910 }
911 } else {
912 if ( mStandAloneMessage ) {
913 // do the special case of a standalone message
914 slotMessageRetrievedForSaving( mStandAloneMessage );
915 mStandAloneMessage = 0;
916 } else {
917 // No more messages. Tell the putjob we are done.
918 TQByteArray data = TQByteArray();
919 mJob->sendAsyncData( data );
920 }
921 }
922}
923
924void KMSaveMsgCommand::slotMessageRetrievedForSaving(KMMessage *msg)
925{
926 if ( msg ) {
927 mData = KMFolderMbox::escapeFrom( msg->asDwString() );
928 KMail::Util::insert( mData, 0, msg->mboxMessageSeparator() );
929 KMail::Util::append( mData, "\n" );
930 msg->setTransferInProgress(false);
931
932 mOffset = 0;
933 TQByteArray data;
934 int size;
935 // Unless it is great than 64 k send the whole message. tdeio buffers for us.
936 if( mData.size() > (unsigned int) MAX_CHUNK_SIZE )
937 size = MAX_CHUNK_SIZE;
938 else
939 size = mData.size();
940
941 data.duplicate( mData, size );
942 mJob->sendAsyncData( data );
943 mOffset += size;
944 }
945 ++mMsgListIndex;
946 // Get rid of the message.
947 if ( msg && msg->parent() && msg->getMsgSerNum() &&
948 mUngetMsgs.contains( msg ) ) {
949 int idx = -1;
950 KMFolder * p = 0;
951 KMMsgDict::instance()->getLocation( msg, &p, &idx );
952 assert( p == msg->parent() ); assert( idx >= 0 );
953 p->unGetMsg( idx );
954 p->close("kmcommand");
955 }
956}
957
958void KMSaveMsgCommand::slotSaveResult(TDEIO::Job *job)
959{
960 if (job->error())
961 {
962 if (job->error() == TDEIO::ERR_FILE_ALREADY_EXIST)
963 {
964 if (KMessageBox::warningContinueCancel(0,
965 i18n("File %1 exists.\nDo you want to replace it?")
966 .arg(mUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
967 == KMessageBox::Continue) {
968 mOffset = 0;
969
970 mJob = TDEIO::put( mUrl, S_IRUSR|S_IWUSR, true, false );
971 mJob->slotTotalSize( mTotalSize );
972 mJob->setAsyncDataEnabled( true );
973 mJob->setReportDataSent( true );
974 connect(mJob, TQ_SIGNAL(dataReq(TDEIO::Job*, TQByteArray &)),
975 TQ_SLOT(slotSaveDataReq()));
976 connect(mJob, TQ_SIGNAL(result(TDEIO::Job*)),
977 TQ_SLOT(slotSaveResult(TDEIO::Job*)));
978 }
979 }
980 else
981 {
982 job->showErrorDialog();
983 setResult( Failed );
984 emit completed( this );
985 deleteLater();
986 }
987 } else {
988 setResult( OK );
989 emit completed( this );
990 deleteLater();
991 }
992}
993
994//-----------------------------------------------------------------------------
995
996KMOpenMsgCommand::KMOpenMsgCommand( TQWidget *parent, const KURL & url,
997 const TQString & encoding )
998 : KMCommand( parent ),
999 mUrl( url ),
1000 mEncoding( encoding )
1001{
1002 setDeletesItself( true );
1003}
1004
1005KMCommand::Result KMOpenMsgCommand::execute()
1006{
1007 if ( mUrl.isEmpty() ) {
1008 mUrl = KFileDialog::getOpenURL( ":OpenMessage", "message/rfc822 application/mbox",
1009 parentWidget(), i18n("Open Message") );
1010 }
1011 if ( mUrl.isEmpty() ) {
1012 setDeletesItself( false );
1013 return Canceled;
1014 }
1015 mJob = TDEIO::get( mUrl, false, false );
1016 mJob->setReportDataSent( true );
1017 connect( mJob, TQ_SIGNAL( data( TDEIO::Job *, const TQByteArray & ) ),
1018 this, TQ_SLOT( slotDataArrived( TDEIO::Job*, const TQByteArray & ) ) );
1019 connect( mJob, TQ_SIGNAL( result( TDEIO::Job * ) ),
1020 TQ_SLOT( slotResult( TDEIO::Job * ) ) );
1021 setEmitsCompletedItself( true );
1022 return OK;
1023}
1024
1025void KMOpenMsgCommand::slotDataArrived( TDEIO::Job *, const TQByteArray & data )
1026{
1027 if ( data.isEmpty() )
1028 return;
1029
1030 mMsgString.append( data.data(), data.size() );
1031}
1032
1033void KMOpenMsgCommand::slotResult( TDEIO::Job *job )
1034{
1035 if ( job->error() ) {
1036 // handle errors
1037 job->showErrorDialog();
1038 setResult( Failed );
1039 emit completed( this );
1040 }
1041 else {
1042 int startOfMessage = 0;
1043 if ( mMsgString.compare( 0, 5, "From ", 5 ) == 0 ) {
1044 startOfMessage = mMsgString.find( '\n' );
1045 if ( startOfMessage == -1 ) {
1046 KMessageBox::sorry( parentWidget(),
1047 i18n( "The file does not contain a message." ) );
1048 setResult( Failed );
1049 emit completed( this );
1050 // Emulate closing of a secondary window so that KMail exits in case it
1051 // was started with the --view command line option. Otherwise an
1052 // invisible KMail would keep running.
1053 SecondaryWindow *win = new SecondaryWindow();
1054 win->close();
1055 win->deleteLater();
1056 deleteLater();
1057 return;
1058 }
1059 startOfMessage += 1; // the message starts after the '\n'
1060 }
1061 // check for multiple messages in the file
1062 bool multipleMessages = true;
1063 int endOfMessage = mMsgString.find( "\nFrom " );
1064 if ( endOfMessage == -1 ) {
1065 endOfMessage = mMsgString.length();
1066 multipleMessages = false;
1067 }
1068 DwMessage *dwMsg = new DwMessage;
1069 dwMsg->FromString( mMsgString.substr( startOfMessage,
1070 endOfMessage - startOfMessage ) );
1071 dwMsg->Parse();
1072 // check whether we have a message ( no headers => this isn't a message )
1073 if ( dwMsg->Headers().NumFields() == 0 ) {
1074 KMessageBox::sorry( parentWidget(),
1075 i18n( "The file does not contain a message." ) );
1076 delete dwMsg; dwMsg = 0;
1077 setResult( Failed );
1078 emit completed( this );
1079 // Emulate closing of a secondary window (see above).
1080 SecondaryWindow *win = new SecondaryWindow();
1081 win->close();
1082 win->deleteLater();
1083 deleteLater();
1084 return;
1085 }
1086 KMMessage *msg = new KMMessage( dwMsg );
1087 msg->setReadyToShow( true );
1088 KMReaderMainWin *win = new KMReaderMainWin();
1089 win->showMsg( mEncoding, msg );
1090 win->show();
1091 if ( multipleMessages )
1092 KMessageBox::information( win,
1093 i18n( "The file contains multiple messages. "
1094 "Only the first message is shown." ) );
1095 setResult( OK );
1096 emit completed( this );
1097 }
1098 deleteLater();
1099}
1100
1101//-----------------------------------------------------------------------------
1102
1103//TODO: ReplyTo, NoQuoteReplyTo, ReplyList, ReplyToAll, ReplyAuthor
1104// are all similar and should be factored
1105KMReplyToCommand::KMReplyToCommand( TQWidget *parent, KMMessage *msg,
1106 const TQString &selection )
1107 : KMCommand( parent, msg ), mSelection( selection )
1108{
1109}
1110
1111KMCommand::Result KMReplyToCommand::execute()
1112{
1113 KCursorSaver busy(KBusyPtr::busy());
1114 KMMessage *msg = retrievedMessage();
1115 if ( !msg || !msg->codec() ) {
1116 return Failed;
1117 }
1118
1119 // Find the account that held the original message
1120 TQString accountName;
1121 KMFolder* parentFolder = msg->parent();
1122 if (parentFolder) {
1123 KMFolderDir* parentFolderDir = parentFolder->parent();
1124 while (parentFolderDir) {
1125 TQString prettyURL = parentFolderDir->prettyURL();
1126 if (prettyURL != "") {
1127 accountName = prettyURL;
1128 }
1129 parentFolderDir = parentFolderDir->parent();
1130 }
1131 }
1132
1133 KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection, false, true, TQString(), accountName );
1134 KMail::Composer * win = KMail::makeComposer( reply );
1135 win->setCharset( msg->codec()->mimeName(), true );
1136 win->setReplyFocus();
1137 win->show();
1138
1139 return OK;
1140}
1141
1142
1143KMNoQuoteReplyToCommand::KMNoQuoteReplyToCommand( TQWidget *parent,
1144 KMMessage *msg )
1145 : KMCommand( parent, msg )
1146{
1147}
1148
1149KMCommand::Result KMNoQuoteReplyToCommand::execute()
1150{
1151 KCursorSaver busy(KBusyPtr::busy());
1152 KMMessage *msg = retrievedMessage();
1153 if ( !msg || !msg->codec() ) {
1154 return Failed;
1155 }
1156 KMMessage *reply = msg->createReply( KMail::ReplySmart, "", true);
1157 KMail::Composer * win = KMail::makeComposer( reply );
1158 win->setCharset(msg->codec()->mimeName(), true);
1159 win->setReplyFocus(false);
1160 win->show();
1161
1162 return OK;
1163}
1164
1165
1166KMReplyListCommand::KMReplyListCommand( TQWidget *parent,
1167 KMMessage *msg, const TQString &selection )
1168 : KMCommand( parent, msg ), mSelection( selection )
1169{
1170}
1171
1172KMCommand::Result KMReplyListCommand::execute()
1173{
1174 KCursorSaver busy(KBusyPtr::busy());
1175 KMMessage *msg = retrievedMessage();
1176 if ( !msg || !msg->codec() ) {
1177 return Failed;
1178 }
1179 KMMessage *reply = msg->createReply( KMail::ReplyList, mSelection);
1180 KMail::Composer * win = KMail::makeComposer( reply );
1181 win->setCharset(msg->codec()->mimeName(), true);
1182 win->setReplyFocus(false);
1183 win->show();
1184
1185 return OK;
1186}
1187
1188
1189KMReplyToAllCommand::KMReplyToAllCommand( TQWidget *parent,
1190 KMMessage *msg, const TQString &selection )
1191 :KMCommand( parent, msg ), mSelection( selection )
1192{
1193}
1194
1195KMCommand::Result KMReplyToAllCommand::execute()
1196{
1197 KCursorSaver busy(KBusyPtr::busy());
1198 KMMessage *msg = retrievedMessage();
1199 if ( !msg || !msg->codec() ) {
1200 return Failed;
1201 }
1202 KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection );
1203 KMail::Composer * win = KMail::makeComposer( reply );
1204 win->setCharset( msg->codec()->mimeName(), true );
1205 win->setReplyFocus();
1206 win->show();
1207
1208 return OK;
1209}
1210
1211
1212KMReplyAuthorCommand::KMReplyAuthorCommand( TQWidget *parent, KMMessage *msg,
1213 const TQString &selection )
1214 : KMCommand( parent, msg ), mSelection( selection )
1215{
1216}
1217
1218KMCommand::Result KMReplyAuthorCommand::execute()
1219{
1220 KCursorSaver busy(KBusyPtr::busy());
1221 KMMessage *msg = retrievedMessage();
1222 if ( !msg || !msg->codec() ) {
1223 return Failed;
1224 }
1225 KMMessage *reply = msg->createReply( KMail::ReplyAuthor, mSelection );
1226 KMail::Composer * win = KMail::makeComposer( reply );
1227 win->setCharset( msg->codec()->mimeName(), true );
1228 win->setReplyFocus();
1229 win->show();
1230
1231 return OK;
1232}
1233
1234
1235KMForwardInlineCommand::KMForwardInlineCommand( TQWidget *parent,
1236 const TQPtrList<KMMsgBase> &msgList, uint identity )
1237 : KMCommand( parent, msgList ),
1238 mIdentity( identity )
1239{
1240}
1241
1242KMForwardInlineCommand::KMForwardInlineCommand( TQWidget *parent,
1243 KMMessage *msg, uint identity )
1244 : KMCommand( parent, msg ),
1245 mIdentity( identity )
1246{
1247}
1248
1249KMCommand::Result KMForwardInlineCommand::execute()
1250{
1251 TQPtrList<KMMessage> msgList = retrievedMsgs();
1252
1253 if (msgList.count() >= 2) { // Multiple forward
1254
1255 uint id = 0;
1256 TQPtrList<KMMessage> linklist;
1257 for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
1258 // set the identity
1259 if (id == 0)
1260 id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
1261
1262 // msgText += msg->createForwardBody();
1263 linklist.append( msg );
1264 }
1265 if ( id == 0 )
1266 id = mIdentity; // use folder identity if no message had an id set
1267 KMMessage *fwdMsg = new KMMessage;
1268 fwdMsg->initHeader( id );
1269 fwdMsg->setAutomaticFields( true );
1270 fwdMsg->setCharset( "utf-8" );
1271 // fwdMsg->setBody( msgText );
1272
1273 for ( KMMessage *msg = linklist.first(); msg; msg = linklist.next() ) {
1274 TemplateParser parser( fwdMsg, TemplateParser::Forward );
1275 parser.setSelection( msg->body() ); // FIXME: Why is this needed?
1276 parser.process( msg, 0, true );
1277
1278 fwdMsg->link( msg, KMMsgStatusForwarded );
1279 }
1280
1281 KCursorSaver busy( KBusyPtr::busy() );
1282 KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
1283 win->setCharset("");
1284 win->show();
1285
1286 } else { // forward a single message at most
1287
1288 KMMessage *msg = msgList.getFirst();
1289 if ( !msg || !msg->codec() )
1290 return Failed;
1291
1292 KCursorSaver busy( KBusyPtr::busy() );
1293 KMMessage *fwdMsg = msg->createForward();
1294
1295 uint id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
1296 if ( id == 0 )
1297 id = mIdentity;
1298 {
1299 KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
1300 win->setCharset( fwdMsg->codec()->mimeName(), true );
1301 win->show();
1302 }
1303 }
1304 return OK;
1305}
1306
1307
1308KMForwardAttachedCommand::KMForwardAttachedCommand( TQWidget *parent,
1309 const TQPtrList<KMMsgBase> &msgList, uint identity, KMail::Composer *win )
1310 : KMCommand( parent, msgList ), mIdentity( identity ),
1311 mWin( TQGuardedPtr<KMail::Composer>( win ))
1312{
1313}
1314
1315KMForwardAttachedCommand::KMForwardAttachedCommand( TQWidget *parent,
1316 KMMessage * msg, uint identity, KMail::Composer *win )
1317 : KMCommand( parent, msg ), mIdentity( identity ),
1318 mWin( TQGuardedPtr< KMail::Composer >( win ))
1319{
1320}
1321
1322KMCommand::Result KMForwardAttachedCommand::execute()
1323{
1324 TQPtrList<KMMessage> msgList = retrievedMsgs();
1325 KMMessage *fwdMsg = new KMMessage;
1326
1327 if (msgList.count() >= 2) {
1328 // don't respect X-KMail-Identity headers because they might differ for
1329 // the selected mails
1330 fwdMsg->initHeader(mIdentity);
1331 }
1332 else if (msgList.count() == 1) {
1333 KMMessage *msg = msgList.getFirst();
1334 fwdMsg->initFromMessage(msg);
1335 fwdMsg->setSubject( msg->forwardSubject() );
1336 }
1337
1338 fwdMsg->setAutomaticFields(true);
1339
1340 KCursorSaver busy(KBusyPtr::busy());
1341 if (!mWin)
1342 mWin = KMail::makeComposer(fwdMsg, mIdentity);
1343
1344 // iterate through all the messages to be forwarded
1345 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
1346 // remove headers that shouldn't be forwarded
1348 msg->removeHeaderField("BCC");
1349 // set the part
1350 KMMessagePart *msgPart = new KMMessagePart;
1351 msgPart->setTypeStr("message");
1352 msgPart->setSubtypeStr("rfc822");
1353 msgPart->setName("forwarded message");
1354 msgPart->setContentDescription(msg->from()+": "+msg->subject());
1355 msgPart->setContentDisposition( "inline" );
1356 msgPart->setMessageBody( KMail::Util::ByteArray( msg->asDwString() ) );
1357
1358 fwdMsg->link(msg, KMMsgStatusForwarded);
1359 mWin->addAttach(msgPart);
1360 }
1361
1362 mWin->show();
1363
1364 return OK;
1365}
1366
1367
1368KMForwardDigestCommand::KMForwardDigestCommand( TQWidget *parent,
1369 const TQPtrList<KMMsgBase> &msgList, uint identity, KMail::Composer *win )
1370 : KMCommand( parent, msgList ), mIdentity( identity ),
1371 mWin( TQGuardedPtr<KMail::Composer>( win ))
1372{
1373}
1374
1375KMForwardDigestCommand::KMForwardDigestCommand( TQWidget *parent,
1376 KMMessage * msg, uint identity, KMail::Composer *win )
1377 : KMCommand( parent, msg ), mIdentity( identity ),
1378 mWin( TQGuardedPtr< KMail::Composer >( win ))
1379{
1380}
1381
1382KMCommand::Result KMForwardDigestCommand::execute()
1383{
1384 TQPtrList<KMMessage> msgList = retrievedMsgs();
1385
1386 if ( msgList.count() < 2 )
1387 return Undefined; // must have more than 1 for a digest
1388
1389 uint id = 0;
1390 KMMessage *fwdMsg = new KMMessage;
1391 KMMessagePart *msgPart = new KMMessagePart;
1392 TQString msgPartText;
1393 int msgCnt = 0; // incase there are some we can't forward for some reason
1394
1395 // dummy header initialization; initialization with the correct identity
1396 // is done below
1397 fwdMsg->initHeader( id );
1398 fwdMsg->setAutomaticFields( true );
1399 fwdMsg->mMsg->Headers().ContentType().CreateBoundary( 1 );
1400 TQCString boundary( fwdMsg->mMsg->Headers().ContentType().Boundary().c_str() );
1401 msgPartText = i18n("\nThis is a MIME digest forward. The content of the"
1402 " message is contained in the attachment(s).\n\n\n");
1403 // iterate through all the messages to be forwarded
1404 for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
1405 // set the identity
1406 if ( id == 0 )
1407 id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
1408 // set the part header
1409 msgPartText += "--";
1410 msgPartText += TQString::fromLatin1( boundary );
1411 msgPartText += "\nContent-Type: MESSAGE/RFC822";
1412 msgPartText += TQString( "; CHARSET=%1" ).arg( TQString(msg->charset()) );
1413 msgPartText += '\n';
1414 DwHeaders dwh;
1415 dwh.MessageId().CreateDefault();
1416 msgPartText += TQString( "Content-ID: %1\n" ).arg( dwh.MessageId().AsString().c_str() );
1417 msgPartText += TQString( "Content-Description: %1" ).arg( msg->subject() );
1418 if ( !msg->subject().contains( "(fwd)" ) )
1419 msgPartText += " (fwd)";
1420 msgPartText += "\n\n";
1421 // remove headers that shouldn't be forwarded
1423 msg->removeHeaderField( "BCC" );
1424 // set the part
1425 msgPartText += msg->headerAsString();
1426 msgPartText += '\n';
1427 msgPartText += msg->body();
1428 msgPartText += '\n'; // eot
1429 msgCnt++;
1430 fwdMsg->link( msg, KMMsgStatusForwarded );
1431 }
1432
1433 if ( id == 0 )
1434 id = mIdentity; // use folder identity if no message had an id set
1435 fwdMsg->initHeader( id );
1436 msgPartText += "--";
1437 msgPartText += TQString::fromLatin1( boundary );
1438 msgPartText += "--\n";
1439 TQCString tmp;
1440 msgPart->setTypeStr( "MULTIPART" );
1441 tmp.sprintf( "Digest; boundary=\"%s\"", boundary.data() );
1442 msgPart->setSubtypeStr( tmp );
1443 msgPart->setName( "unnamed" );
1444 msgPart->setCte( DwMime::kCte7bit ); // does it have to be 7bit?
1445 msgPart->setContentDescription( TQString( "Digest of %1 messages." ).arg( msgCnt ) );
1446 // THIS HAS TO BE AFTER setCte()!!!!
1447 msgPart->setBodyEncoded( TQCString( msgPartText.ascii() ) );
1448 KCursorSaver busy( KBusyPtr::busy() );
1449 KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
1450 win->addAttach( msgPart );
1451 win->show();
1452 return OK;
1453}
1454
1455KMRedirectCommand::KMRedirectCommand( TQWidget *parent,
1456 KMMessage *msg )
1457 : KMCommand( parent, msg )
1458{
1459}
1460
1461KMCommand::Result KMRedirectCommand::execute()
1462{
1463 KMMessage *msg = retrievedMessage();
1464 if ( !msg || !msg->codec() )
1465 return Failed;
1466
1467 RedirectDialog dlg( parentWidget(), "redirect", true,
1468 kmkernel->msgSender()->sendImmediate() );
1469 if (dlg.exec()==TQDialog::Rejected) return Failed;
1470
1471 KMMessage *newMsg = msg->createRedirect( dlg.to() );
1472 KMFilterAction::sendMDN( msg, KMime::MDN::Dispatched );
1473
1474 const KMail::MessageSender::SendMethod method = dlg.sendImmediate()
1475 ? KMail::MessageSender::SendImmediate
1476 : KMail::MessageSender::SendLater;
1477 if ( !kmkernel->msgSender()->send( newMsg, method ) ) {
1478 kdDebug(5006) << "KMRedirectCommand: could not redirect message (sending failed)" << endl;
1479 return Failed; // error: couldn't send
1480 }
1481 return OK;
1482}
1483
1484
1485KMCustomReplyToCommand::KMCustomReplyToCommand( TQWidget *parent, KMMessage *msg,
1486 const TQString &selection,
1487 const TQString &tmpl )
1488 : KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
1489{
1490}
1491
1492KMCommand::Result KMCustomReplyToCommand::execute()
1493{
1494 KCursorSaver busy(KBusyPtr::busy());
1495 KMMessage *msg = retrievedMessage();
1496 if ( !msg || !msg->codec() ) {
1497 return Failed;
1498 }
1499 KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection,
1500 false, true, mTemplate );
1501 KMail::Composer * win = KMail::makeComposer( reply );
1502 win->setCharset( msg->codec()->mimeName(), true );
1503 win->setReplyFocus();
1504 win->show();
1505
1506 return OK;
1507}
1508
1509
1510KMCustomReplyAllToCommand::KMCustomReplyAllToCommand( TQWidget *parent, KMMessage *msg,
1511 const TQString &selection,
1512 const TQString &tmpl )
1513 : KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
1514{
1515}
1516
1517KMCommand::Result KMCustomReplyAllToCommand::execute()
1518{
1519 KCursorSaver busy(KBusyPtr::busy());
1520 KMMessage *msg = retrievedMessage();
1521 if ( !msg || !msg->codec() ) {
1522 return Failed;
1523 }
1524 KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection,
1525 false, true, mTemplate );
1526 KMail::Composer * win = KMail::makeComposer( reply );
1527 win->setCharset( msg->codec()->mimeName(), true );
1528 win->setReplyFocus();
1529 win->show();
1530
1531 return OK;
1532}
1533
1534
1535KMCustomForwardCommand::KMCustomForwardCommand( TQWidget *parent,
1536 const TQPtrList<KMMsgBase> &msgList, uint identity, const TQString &tmpl )
1537 : KMCommand( parent, msgList ),
1538 mIdentity( identity ), mTemplate( tmpl )
1539{
1540}
1541
1542KMCustomForwardCommand::KMCustomForwardCommand( TQWidget *parent,
1543 KMMessage *msg, uint identity, const TQString &tmpl )
1544 : KMCommand( parent, msg ),
1545 mIdentity( identity ), mTemplate( tmpl )
1546{
1547}
1548
1549KMCommand::Result KMCustomForwardCommand::execute()
1550{
1551 TQPtrList<KMMessage> msgList = retrievedMsgs();
1552
1553 if (msgList.count() >= 2) { // Multiple forward
1554
1555 uint id = 0;
1556 TQPtrList<KMMessage> linklist;
1557 for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
1558 // set the identity
1559 if (id == 0)
1560 id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
1561
1562 // msgText += msg->createForwardBody();
1563 linklist.append( msg );
1564 }
1565 if ( id == 0 )
1566 id = mIdentity; // use folder identity if no message had an id set
1567 KMMessage *fwdMsg = new KMMessage;
1568 fwdMsg->initHeader( id );
1569 fwdMsg->setAutomaticFields( true );
1570 fwdMsg->setCharset( "utf-8" );
1571 // fwdMsg->setBody( msgText );
1572
1573 for ( KMMessage *msg = linklist.first(); msg; msg = linklist.next() ) {
1574 TemplateParser parser( fwdMsg, TemplateParser::Forward );
1575 parser.setSelection( msg->body() ); // FIXME: Why is this needed?
1576 parser.process( msg, 0, true );
1577
1578 fwdMsg->link( msg, KMMsgStatusForwarded );
1579 }
1580
1581 KCursorSaver busy( KBusyPtr::busy() );
1582 KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
1583 win->setCharset("");
1584 win->show();
1585
1586 } else { // forward a single message at most
1587
1588 KMMessage *msg = msgList.getFirst();
1589 if ( !msg || !msg->codec() )
1590 return Failed;
1591
1592 KCursorSaver busy( KBusyPtr::busy() );
1593 KMMessage *fwdMsg = msg->createForward( mTemplate );
1594
1595 uint id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
1596 if ( id == 0 )
1597 id = mIdentity;
1598 {
1599 KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
1600 win->setCharset( fwdMsg->codec()->mimeName(), true );
1601 win->show();
1602 }
1603 }
1604 return OK;
1605}
1606
1607
1608KMPrintCommand::KMPrintCommand( TQWidget *parent, KMMessage *msg,
1609 const KMail::HeaderStyle *headerStyle,
1610 const KMail::HeaderStrategy *headerStrategy,
1611 bool htmlOverride, bool htmlLoadExtOverride,
1612 bool useFixedFont, const TQString & encoding )
1613 : KMCommand( parent, msg ),
1614 mHeaderStyle( headerStyle ), mHeaderStrategy( headerStrategy ),
1615 mHtmlOverride( htmlOverride ),
1616 mHtmlLoadExtOverride( htmlLoadExtOverride ),
1617 mUseFixedFont( useFixedFont ), mEncoding( encoding )
1618{
1619 if ( GlobalSettings::useDefaultFonts() )
1620 mOverrideFont = TDEGlobalSettings::generalFont();
1621 else {
1622 TDEConfigGroup fonts( KMKernel::config(), "Fonts" );
1623 TQString tmp = fonts.readEntry( "print-font", TDEGlobalSettings::generalFont().toString() );
1624 mOverrideFont.fromString( tmp );
1625 }
1626}
1627
1628
1629void KMPrintCommand::setOverrideFont( const TQFont& font )
1630{
1631 mOverrideFont = font;
1632}
1633
1634KMCommand::Result KMPrintCommand::execute()
1635{
1636 KMReaderWin printWin( 0, 0, 0 );
1637 printWin.setPrinting( true );
1638 printWin.readConfig();
1639 if ( mHeaderStyle != 0 && mHeaderStrategy != 0 )
1640 printWin.setHeaderStyleAndStrategy( mHeaderStyle, mHeaderStrategy );
1641 printWin.setHtmlOverride( mHtmlOverride );
1642 printWin.setHtmlLoadExtOverride( mHtmlLoadExtOverride );
1643 printWin.setUseFixedFont( mUseFixedFont );
1644 printWin.setOverrideEncoding( mEncoding );
1645 printWin.cssHelper()->setPrintFont( mOverrideFont );
1646 printWin.setDecryptMessageOverwrite( true );
1647 printWin.setMsg( retrievedMessage(), true );
1648 printWin.printMsg();
1649
1650 return OK;
1651}
1652
1653
1654KMSeStatusCommand::KMSeStatusCommand( KMMsgStatus status,
1655 const TQValueList<TQ_UINT32> &serNums, bool toggle )
1656 : mStatus( status ), mSerNums( serNums ), mToggle( toggle )
1657{
1658}
1659
1660KMCommand::Result KMSeStatusCommand::execute()
1661{
1662 TQValueListIterator<TQ_UINT32> it;
1663 int idx = -1;
1664 KMFolder *folder = 0;
1665 bool parenStatus = false;
1666
1667 // Toggle actions on threads toggle the whole thread
1668 // depending on the state of the parent.
1669 if (mToggle) {
1670 KMMsgBase *msg;
1671 KMMsgDict::instance()->getLocation( *mSerNums.begin(), &folder, &idx );
1672 if (folder) {
1673 msg = folder->getMsgBase(idx);
1674 if (msg && (msg->status()&mStatus))
1675 parenStatus = true;
1676 else
1677 parenStatus = false;
1678 }
1679 }
1680 TQMap< KMFolder*, TQValueList<int> > folderMap;
1681 for ( it = mSerNums.begin(); it != mSerNums.end(); ++it ) {
1682 KMMsgDict::instance()->getLocation( *it, &folder, &idx );
1683 if (folder) {
1684 if (mToggle) {
1685 KMMsgBase *msg = folder->getMsgBase(idx);
1686 // check if we are already at the target toggle state
1687 if (msg) {
1688 bool myStatus;
1689 if (msg->status()&mStatus)
1690 myStatus = true;
1691 else
1692 myStatus = false;
1693 if (myStatus != parenStatus)
1694 continue;
1695 }
1696 }
1697 /* Collect the ids for each folder in a separate list and
1698 send them off in one go at the end. */
1699 folderMap[folder].append(idx);
1700 }
1701 }
1702 TQMapIterator< KMFolder*, TQValueList<int> > it2 = folderMap.begin();
1703 while ( it2 != folderMap.end() ) {
1704 KMFolder *f = it2.key();
1705 f->setStatus( (*it2), mStatus, mToggle );
1706 ++it2;
1707 }
1708 //tdeApp->dcopClient()->emitDCOPSignal( "unreadCountChanged()", TQByteArray() );
1709
1710 return OK;
1711}
1712
1713
1714KMFilterCommand::KMFilterCommand( const TQCString &field, const TQString &value )
1715 : mField( field ), mValue( value )
1716{
1717}
1718
1719KMCommand::Result KMFilterCommand::execute()
1720{
1721 kmkernel->filterMgr()->createFilter( mField, mValue );
1722
1723 return OK;
1724}
1725
1726
1727KMFilterActionCommand::KMFilterActionCommand( TQWidget *parent,
1728 const TQPtrList<KMMsgBase> &msgList,
1729 KMFilter *filter )
1730 : KMCommand( parent, msgList ), mFilter( filter )
1731{
1732 TQPtrListIterator<KMMsgBase> it(msgList);
1733 while ( it.current() ) {
1734 serNumList.append( (*it)->getMsgSerNum() );
1735 ++it;
1736 }
1737}
1738
1739KMCommand::Result KMFilterActionCommand::execute()
1740{
1741 KCursorSaver busy( KBusyPtr::busy() );
1742
1743 int msgCount = 0;
1744 int msgCountToFilter = serNumList.count();
1745 ProgressItem* progressItem =
1746 ProgressManager::createProgressItem ( "filter"+ProgressManager::getUniqueID(),
1747 i18n( "Filtering messages" ) );
1748 progressItem->setTotalItems( msgCountToFilter );
1749 TQValueList<TQ_UINT32>::const_iterator it;
1750 for ( it = serNumList.begin(); it != serNumList.end(); it++ ) {
1751 TQ_UINT32 serNum = *it;
1752 int diff = msgCountToFilter - ++msgCount;
1753 if ( diff < 10 || !( msgCount % 20 ) || msgCount <= 10 ) {
1754 progressItem->updateProgress();
1755 TQString statusMsg = i18n("Filtering message %1 of %2");
1756 statusMsg = statusMsg.arg( msgCount ).arg( msgCountToFilter );
1757 KPIM::BroadcastStatus::instance()->setStatusMsg( statusMsg );
1758 tdeApp->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput, 50 );
1759 }
1760
1761 int filterResult = kmkernel->filterMgr()->process( serNum, mFilter );
1762 if (filterResult == 2) {
1763 // something went horribly wrong (out of space?)
1764 perror("Critical error");
1765 kmkernel->emergencyExit( i18n("Not enough free disk space?" ));
1766 }
1767 progressItem->incCompletedItems();
1768 }
1769
1770 progressItem->setComplete();
1771 progressItem = 0;
1772 return OK;
1773}
1774
1775
1776KMMetaFilterActionCommand::KMMetaFilterActionCommand( KMFilter *filter,
1777 KMHeaders *headers,
1778 KMMainWidget *main )
1779 : TQObject( main ),
1780 mFilter( filter ), mHeaders( headers ), mMainWidget( main )
1781{
1782}
1783
1784void KMMetaFilterActionCommand::start()
1785{
1786 if (ActionScheduler::isEnabled() ) {
1787 // use action scheduler
1788 KMFilterMgr::FilterSet set = KMFilterMgr::All;
1789 TQValueList<KMFilter*> filters;
1790 filters.append( mFilter );
1791 ActionScheduler *scheduler = new ActionScheduler( set, filters, mHeaders );
1792 scheduler->setAlwaysMatch( true );
1793 scheduler->setAutoDestruct( true );
1794
1795 int contentX, contentY;
1796 HeaderItem *nextItem = mHeaders->prepareMove( &contentX, &contentY );
1797 TQPtrList<KMMsgBase> msgList = *mHeaders->selectedMsgs(true);
1798 mHeaders->finalizeMove( nextItem, contentX, contentY );
1799
1800 for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
1801 scheduler->execFilters( msg );
1802 } else {
1803 KMCommand *filterCommand =
1804 new KMFilterActionCommand( mMainWidget,
1805 *mHeaders->selectedMsgs(), mFilter );
1806 filterCommand->start();
1807 int contentX, contentY;
1808 HeaderItem *item = mHeaders->prepareMove( &contentX, &contentY );
1809 mHeaders->finalizeMove( item, contentX, contentY );
1810 }
1811}
1812
1813FolderShortcutCommand::FolderShortcutCommand( KMMainWidget *mainwidget,
1814 KMFolder *folder )
1815 : mMainWidget( mainwidget ), mFolder( folder ), mAction( 0 )
1816{
1817}
1818
1819
1820FolderShortcutCommand::~FolderShortcutCommand()
1821{
1822 if ( mAction ) mAction->unplugAll();
1823 delete mAction;
1824}
1825
1826void FolderShortcutCommand::start()
1827{
1828 mMainWidget->slotSelectFolder( mFolder );
1829}
1830
1831void FolderShortcutCommand::setAction( TDEAction* action )
1832{
1833 mAction = action;
1834}
1835
1836KMMailingListFilterCommand::KMMailingListFilterCommand( TQWidget *parent,
1837 KMMessage *msg )
1838 : KMCommand( parent, msg )
1839{
1840}
1841
1842KMCommand::Result KMMailingListFilterCommand::execute()
1843{
1844 TQCString name;
1845 TQString value;
1846 KMMessage *msg = retrievedMessage();
1847 if (!msg)
1848 return Failed;
1849
1850 if ( !MailingList::name( msg, name, value ).isEmpty() ) {
1851 kmkernel->filterMgr()->createFilter( name, value );
1852 return OK;
1853 }
1854 else
1855 return Failed;
1856}
1857
1858
1859void KMMenuCommand::folderToPopupMenu(bool move,
1860 TQObject *receiver, KMMenuToFolder *aMenuToFolder, TQPopupMenu *menu )
1861{
1862 while ( menu->count() )
1863 {
1864 TQPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
1865 if (popup)
1866 delete popup;
1867 else
1868 menu->removeItemAt( 0 );
1869 }
1870
1871 if (!kmkernel->imapFolderMgr()->dir().first() &&
1872 !kmkernel->dimapFolderMgr()->dir().first())
1873 { // only local folders
1874 makeFolderMenu( &kmkernel->folderMgr()->dir(), move,
1875 receiver, aMenuToFolder, menu );
1876 } else {
1877 // operate on top-level items
1878 TQPopupMenu* subMenu = new TQPopupMenu(menu);
1879 makeFolderMenu( &kmkernel->folderMgr()->dir(),
1880 move, receiver, aMenuToFolder, subMenu );
1881 menu->insertItem( i18n( "Local Folders" ), subMenu );
1882 KMFolderDir* fdir = &kmkernel->imapFolderMgr()->dir();
1883 for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
1884 if (node->isDir())
1885 continue;
1886 subMenu = new TQPopupMenu(menu);
1887 makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
1888 menu->insertItem( node->label(), subMenu );
1889 }
1890 fdir = &kmkernel->dimapFolderMgr()->dir();
1891 for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
1892 if (node->isDir())
1893 continue;
1894 subMenu = new TQPopupMenu(menu);
1895 makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
1896 menu->insertItem( node->label(), subMenu );
1897 }
1898 }
1899}
1900
1901void KMMenuCommand::makeFolderMenu(KMFolderNode* node, bool move,
1902 TQObject *receiver, KMMenuToFolder *aMenuToFolder, TQPopupMenu *menu )
1903{
1904 // connect the signals
1905 if (move)
1906 {
1907 disconnect(menu, TQ_SIGNAL(activated(int)), receiver,
1908 TQ_SLOT(moveSelectedToFolder(int)));
1909 connect(menu, TQ_SIGNAL(activated(int)), receiver,
1910 TQ_SLOT(moveSelectedToFolder(int)));
1911 } else {
1912 disconnect(menu, TQ_SIGNAL(activated(int)), receiver,
1913 TQ_SLOT(copySelectedToFolder(int)));
1914 connect(menu, TQ_SIGNAL(activated(int)), receiver,
1915 TQ_SLOT(copySelectedToFolder(int)));
1916 }
1917
1918 KMFolder *folder = 0;
1919 KMFolderDir *folderDir = 0;
1920 if (node->isDir()) {
1921 folderDir = static_cast<KMFolderDir*>(node);
1922 } else {
1923 folder = static_cast<KMFolder*>(node);
1924 folderDir = folder->child();
1925 }
1926
1927 if (folder && !folder->noContent())
1928 {
1929 int menuId;
1930 if (move)
1931 menuId = menu->insertItem(i18n("Move to This Folder"));
1932 else
1933 menuId = menu->insertItem(i18n("Copy to This Folder"));
1934 aMenuToFolder->insert( menuId, folder );
1935 menu->setItemEnabled( menuId, !folder->isReadOnly() );
1936 menu->insertSeparator();
1937 }
1938
1939 if (!folderDir)
1940 return;
1941
1942 for (KMFolderNode *it = folderDir->first(); it; it = folderDir->next() ) {
1943 if (it->isDir())
1944 continue;
1945 KMFolder *child = static_cast<KMFolder*>(it);
1946 TQString label = child->label();
1947 label.replace("&","&&");
1948 if (child->child() && child->child()->first()) {
1949 // descend
1950 TQPopupMenu *subMenu = new TQPopupMenu(menu, "subMenu");
1951 makeFolderMenu( child, move, receiver,
1952 aMenuToFolder, subMenu );
1953 menu->insertItem( label, subMenu );
1954 } else {
1955 // insert an item
1956 int menuId = menu->insertItem( label );
1957 aMenuToFolder->insert( menuId, child );
1958 menu->setItemEnabled( menuId, !child->isReadOnly() );
1959 }
1960 }
1961 return;
1962}
1963
1964
1965KMCopyCommand::KMCopyCommand( KMFolder* destFolder,
1966 const TQPtrList<KMMsgBase> &msgList )
1967:mDestFolder( destFolder ), mMsgList( msgList )
1968{
1969 setDeletesItself( true );
1970}
1971
1972KMCopyCommand::KMCopyCommand( KMFolder* destFolder, KMMessage * msg )
1973 :mDestFolder( destFolder )
1974{
1975 setDeletesItself( true );
1976 mMsgList.append( &msg->toMsgBase() );
1977}
1978
1979KMCommand::Result KMCopyCommand::execute()
1980{
1981 KMMsgBase *msgBase;
1982 KMMessage *msg, *newMsg;
1983 int idx = -1;
1984 bool isMessage;
1985 TQPtrList<KMMessage> list;
1986 TQPtrList<KMMessage> localList;
1987
1988 if (mDestFolder && mDestFolder->open("kmcommand") != 0)
1989 {
1990 deleteLater();
1991 return Failed;
1992 }
1993
1994 setEmitsCompletedItself( true );
1995 KCursorSaver busy(KBusyPtr::busy());
1996
1997 for (msgBase = mMsgList.first(); msgBase; msgBase = mMsgList.next() )
1998 {
1999 KMFolder *srcFolder = msgBase->parent();
2000 if (( isMessage = msgBase->isMessage() ))
2001 {
2002 msg = static_cast<KMMessage*>(msgBase);
2003 } else {
2004 idx = srcFolder->find(msgBase);
2005 assert(idx != -1);
2006 msg = srcFolder->getMsg(idx);
2007 // corrupt IMAP cache, see FolderStorage::getMsg()
2008 if ( msg == 0 ) {
2009 KMessageBox::error( parentWidget(), i18n("Corrupt IMAP cache detected in folder %1. "
2010 "Copying of messages aborted.").arg( srcFolder->prettyURL() ) );
2011 deleteLater();
2012 return Failed;
2013 }
2014 }
2015
2016 if (srcFolder && mDestFolder &&
2017 (srcFolder->folderType()== KMFolderTypeImap) &&
2018 (mDestFolder->folderType() == KMFolderTypeImap) &&
2019 (static_cast<KMFolderImap*>(srcFolder->storage())->account() ==
2020 static_cast<KMFolderImap*>(mDestFolder->storage())->account()))
2021 {
2022 // imap => imap with same account
2023 list.append(msg);
2024 } else {
2025 newMsg = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
2026 newMsg->setComplete(msg->isComplete());
2027 // make sure the attachment state is only calculated when it's complete
2028 if (!newMsg->isComplete())
2029 newMsg->setReadyToShow(false);
2030 newMsg->setStatus(msg->status());
2031
2032 if (srcFolder && !newMsg->isComplete())
2033 {
2034 // imap => others
2035 newMsg->setParent(msg->parent());
2036 FolderJob *job = srcFolder->createJob(newMsg);
2037 job->setCancellable( false );
2038 mPendingJobs << job;
2039 connect(job, TQ_SIGNAL(messageRetrieved(KMMessage*)),
2040 mDestFolder, TQ_SLOT(reallyAddCopyOfMsg(KMMessage*)));
2041 connect( job, TQ_SIGNAL(result(KMail::FolderJob*)),
2042 this, TQ_SLOT(slotJobFinished(KMail::FolderJob*)) );
2043 job->start();
2044 } else {
2045 // local => others
2046 localList.append(newMsg);
2047 }
2048 }
2049
2050 if (srcFolder && !isMessage && list.isEmpty())
2051 {
2052 assert(idx != -1);
2053 srcFolder->unGetMsg( idx );
2054 }
2055
2056 } // end for
2057
2058 bool deleteNow = false;
2059 if (!localList.isEmpty())
2060 {
2061 TQValueList<int> index;
2062 mDestFolder->addMsg( localList, index );
2063 for ( TQValueListIterator<int> it = index.begin(); it != index.end(); ++it ) {
2064 mDestFolder->unGetMsg( *it );
2065 }
2066 if ( mDestFolder->folderType() == KMFolderTypeImap ) {
2067 if ( mPendingJobs.isEmpty() ) {
2068 // wait for the end of the copy before closing the folder
2069 KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
2070 connect( imapDestFolder, TQ_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
2071 this, TQ_SLOT( slotFolderComplete( KMFolderImap*, bool ) ) );
2072 }
2073 } else {
2074 deleteNow = list.isEmpty() && mPendingJobs.isEmpty(); // we're done if there are no other mails we need to fetch
2075 }
2076 }
2077
2078//TODO: Get rid of the other cases just use this one for all types of folder
2079//TODO: requires adding copyMsg and getFolder methods to KMFolder.h
2080 if (!list.isEmpty())
2081 {
2082 // copy the message(s); note: the list is empty afterwards!
2083 KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
2084 connect( imapDestFolder, TQ_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
2085 this, TQ_SLOT( slotFolderComplete( KMFolderImap*, bool ) ) );
2086 imapDestFolder->copyMsg(list);
2087 imapDestFolder->getFolder();
2088 }
2089
2090 // only close the folder and delete the job if we're done
2091 // otherwise this is done in slotMsgAdded or slotFolderComplete
2092 if ( deleteNow )
2093 {
2094 mDestFolder->close("kmcommand");
2095 setResult( OK );
2096 emit completed( this );
2097 deleteLater();
2098 }
2099
2100 return OK;
2101}
2102
2103void KMCopyCommand::slotJobFinished(KMail::FolderJob * job)
2104{
2105 mPendingJobs.remove( job );
2106 if ( job->error() ) {
2107 kdDebug(5006) << k_funcinfo << "folder job failed: " << job->error() << endl;
2108 // kill all pending jobs
2109 for ( TQValueList<KMail::FolderJob*>::Iterator it = mPendingJobs.begin(); it != mPendingJobs.end(); ++it ) {
2110 disconnect( (*it), TQ_SIGNAL(result(KMail::FolderJob*)),
2111 this, TQ_SLOT(slotJobFinished(KMail::FolderJob*)) );
2112 (*it)->kill();
2113 }
2114 mPendingJobs.clear();
2115 setResult( Failed );
2116 }
2117
2118 if ( mPendingJobs.isEmpty() )
2119 {
2120 mDestFolder->close("kmcommand");
2121 emit completed( this );
2122 deleteLater();
2123 }
2124}
2125
2126void KMCopyCommand::slotFolderComplete( KMFolderImap*, bool success )
2127{
2128 kdDebug(5006) << k_funcinfo << success << endl;
2129 if ( !success )
2130 setResult( Failed );
2131 mDestFolder->close( "kmcommand" );
2132 emit completed( this );
2133 deleteLater();
2134}
2135
2136
2137KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
2138 const TQPtrList<KMMsgBase> &msgList)
2139 : mDestFolder( destFolder ), mProgressItem( 0 )
2140{
2141 TQPtrList<KMMsgBase> tmp = msgList;
2142 for ( KMMsgBase *msgBase = tmp.first(); msgBase; msgBase = tmp.next() )
2143 mSerNumList.append( msgBase->getMsgSerNum() );
2144}
2145
2146KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
2147 KMMessage *msg )
2148 : mDestFolder( destFolder ), mProgressItem( 0 )
2149{
2150 mSerNumList.append( msg->getMsgSerNum() );
2151}
2152
2153KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
2154 KMMsgBase *msgBase )
2155 : mDestFolder( destFolder ), mProgressItem( 0 )
2156{
2157 mSerNumList.append( msgBase->getMsgSerNum() );
2158}
2159
2160KMMoveCommand::KMMoveCommand( TQ_UINT32 )
2161 : mProgressItem( 0 )
2162{
2163}
2164
2165KMCommand::Result KMMoveCommand::execute()
2166{
2167 setEmitsCompletedItself( true );
2168 setDeletesItself( true );
2169 typedef TQMap< KMFolder*, TQPtrList<KMMessage>* > FolderToMessageListMap;
2170 FolderToMessageListMap folderDeleteList;
2171
2172 if (mDestFolder && mDestFolder->open("kmcommand") != 0) {
2173 completeMove( Failed );
2174 return Failed;
2175 }
2176 KCursorSaver busy(KBusyPtr::busy());
2177
2178 // TODO set SSL state according to source and destfolder connection?
2179 Q_ASSERT( !mProgressItem );
2180 mProgressItem =
2181 ProgressManager::createProgressItem (
2182 "move"+ProgressManager::getUniqueID(),
2183 mDestFolder ? i18n( "Moving messages" ) : i18n( "Deleting messages" ) );
2184 connect( mProgressItem, TQ_SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
2185 this, TQ_SLOT( slotMoveCanceled() ) );
2186
2187 KMMessage *msg;
2188 int rc = 0;
2189 int index;
2190 TQPtrList<KMMessage> list;
2191 int undoId = -1;
2192 mCompleteWithAddedMsg = false;
2193
2194 if (mDestFolder) {
2195 connect (mDestFolder, TQ_SIGNAL(msgAdded(KMFolder*, TQ_UINT32)),
2196 this, TQ_SLOT(slotMsgAddedToDestFolder(KMFolder*, TQ_UINT32)));
2197 mLostBoys = mSerNumList;
2198 }
2199 mProgressItem->setTotalItems( mSerNumList.count() );
2200
2201 for ( TQValueList<TQ_UINT32>::ConstIterator it = mSerNumList.constBegin(); it != mSerNumList.constEnd(); ++it ) {
2202 if ( *it == 0 ) {
2203 kdDebug(5006) << k_funcinfo << "serial number == 0!" << endl;
2204 continue; // invalid message
2205 }
2206 KMFolder *srcFolder = 0;
2207 int idx = -1;
2208 KMMsgDict::instance()->getLocation( *it, &srcFolder, &idx );
2209 if (srcFolder == mDestFolder)
2210 continue;
2211 assert(srcFolder);
2212 assert(idx != -1);
2213 if ( !srcFolder->isOpened() ) {
2214 srcFolder->open( "kmmovecommand" );
2215 mOpenedFolders.append( srcFolder );
2216 }
2217 msg = srcFolder->getMsg(idx);
2218 if ( !msg ) {
2219 kdDebug(5006) << k_funcinfo << "No message found for serial number " << *it << endl;
2220 continue;
2221 }
2222 bool undo = msg->enableUndo();
2223
2224 if ( msg && msg->transferInProgress() &&
2225 srcFolder->folderType() == KMFolderTypeImap )
2226 {
2227 // cancel the download
2228 msg->setTransferInProgress( false, true );
2229 static_cast<KMFolderImap*>(srcFolder->storage())->ignoreJobsForMessage( msg );
2230 }
2231
2232 if (mDestFolder) {
2233 if (mDestFolder->folderType() == KMFolderTypeImap) {
2234 /* If we are moving to an imap folder, connect to it's completed
2235 * signal so we notice when all the mails should have showed up in it
2236 * but haven't for some reason. */
2237 KMFolderImap *imapFolder = static_cast<KMFolderImap*> ( mDestFolder->storage() );
2238 disconnect (imapFolder, TQ_SIGNAL(folderComplete( KMFolderImap*, bool )),
2239 this, TQ_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
2240
2241 connect (imapFolder, TQ_SIGNAL(folderComplete( KMFolderImap*, bool )),
2242 this, TQ_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
2243 list.append(msg);
2244 } else {
2245 // We are moving to a local folder.
2246 if ( srcFolder->folderType() == KMFolderTypeImap )
2247 {
2248 // do not complete here but wait until all messages are transferred
2249 mCompleteWithAddedMsg = true;
2250 }
2251 rc = mDestFolder->moveMsg(msg, &index);
2252 if (rc == 0 && index != -1) {
2253 KMMsgBase *mb = mDestFolder->unGetMsg( mDestFolder->count() - 1 );
2254 if (undo && mb)
2255 {
2256 if ( undoId == -1 )
2257 undoId = kmkernel->undoStack()->newUndoAction( srcFolder, mDestFolder );
2258 kmkernel->undoStack()->addMsgToAction( undoId, mb->getMsgSerNum() );
2259 }
2260 } else if (rc != 0) {
2261 // Something went wrong. Stop processing here, it is likely that the
2262 // other moves would fail as well.
2263 completeMove( Failed );
2264 return Failed;
2265 }
2266 }
2267 } else {
2268 // really delete messages that are already in the trash folder or if
2269 // we are really, really deleting, not just moving to trash
2270 if (srcFolder->folderType() == KMFolderTypeImap) {
2271 if (!folderDeleteList[srcFolder])
2272 folderDeleteList[srcFolder] = new TQPtrList<KMMessage>;
2273 folderDeleteList[srcFolder]->append( msg );
2274 } else {
2275 srcFolder->removeMsg(idx);
2276 delete msg;
2277 }
2278 }
2279 }
2280 if (!list.isEmpty() && mDestFolder) {
2281 // will be completed with folderComplete signal
2282 mDestFolder->moveMsg(list, &index);
2283 } else {
2284 FolderToMessageListMap::Iterator it;
2285 for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) {
2286 it.key()->removeMsg(*it.data());
2287 delete it.data();
2288 }
2289 if ( !mCompleteWithAddedMsg ) {
2290 // imap folders will be completed in slotMsgAddedToDestFolder
2291 completeMove( OK );
2292 }
2293 }
2294
2295 return OK;
2296}
2297
2298void KMMoveCommand::slotImapFolderCompleted(KMFolderImap* imapFolder, bool success)
2299{
2300 disconnect (imapFolder, TQ_SIGNAL(folderComplete( KMFolderImap*, bool )),
2301 this, TQ_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
2302 if ( success ) {
2303 // the folder was checked successfully but we were still called, so check
2304 // if we are still waiting for messages to show up. If so, uidValidity
2305 // changed, or something else went wrong. Clean up.
2306
2307 /* Unfortunately older UW imap servers change uid validity for each put job.
2308 * Yes, it is really that broken. *sigh* So we cannot report error here, I guess. */
2309 if ( !mLostBoys.isEmpty() ) {
2310 kdDebug(5006) << "### Not all moved messages reported back that they were " << endl
2311 << "### added to the target folder. Did uidValidity change? " << endl;
2312 }
2313 completeMove( OK );
2314 } else {
2315 // Should we inform the user here or leave that to the caller?
2316 completeMove( Failed );
2317 }
2318}
2319
2320void KMMoveCommand::slotMsgAddedToDestFolder(KMFolder *folder, TQ_UINT32 serNum)
2321{
2322 if ( folder != mDestFolder || mLostBoys.find( serNum ) == mLostBoys.end() ) {
2323 //kdDebug(5006) << "KMMoveCommand::msgAddedToDestFolder different "
2324 // "folder or invalid serial number." << endl;
2325 return;
2326 }
2327 mLostBoys.remove(serNum);
2328 if ( mLostBoys.isEmpty() ) {
2329 // we are done. All messages transferred to the host succesfully
2330 disconnect (mDestFolder, TQ_SIGNAL(msgAdded(KMFolder*, TQ_UINT32)),
2331 this, TQ_SLOT(slotMsgAddedToDestFolder(KMFolder*, TQ_UINT32)));
2332 if (mDestFolder && mDestFolder->folderType() != KMFolderTypeImap) {
2333 mDestFolder->sync();
2334 }
2335 if ( mCompleteWithAddedMsg ) {
2336 completeMove( OK );
2337 }
2338 } else {
2339 if ( mProgressItem ) {
2340 mProgressItem->incCompletedItems();
2341 mProgressItem->updateProgress();
2342 }
2343 }
2344}
2345
2346void KMMoveCommand::completeMove( Result result )
2347{
2348 if ( mDestFolder )
2349 mDestFolder->close("kmcommand");
2350 while ( !mOpenedFolders.empty() ) {
2351 KMFolder *folder = mOpenedFolders.back();
2352 mOpenedFolders.pop_back();
2353 folder->close("kmcommand");
2354 }
2355 if ( mProgressItem ) {
2356 mProgressItem->setComplete();
2357 mProgressItem = 0;
2358 }
2359 setResult( result );
2360 emit completed( this );
2361 deleteLater();
2362}
2363
2364void KMMoveCommand::slotMoveCanceled()
2365{
2366 completeMove( Canceled );
2367}
2368
2369// srcFolder doesn't make much sense for searchFolders
2370KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder,
2371 const TQPtrList<KMMsgBase> &msgList )
2372:KMMoveCommand( findTrashFolder( srcFolder ), msgList)
2373{
2374 srcFolder->open("kmcommand");
2375 mOpenedFolders.push_back( srcFolder );
2376}
2377
2378KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg )
2379:KMMoveCommand( findTrashFolder( srcFolder ), msg)
2380{
2381 srcFolder->open("kmcommand");
2382 mOpenedFolders.push_back( srcFolder );
2383}
2384
2385KMDeleteMsgCommand::KMDeleteMsgCommand( TQ_UINT32 sernum )
2386:KMMoveCommand( sernum )
2387{
2388 if ( !sernum ) {
2389 setDestFolder( 0 );
2390 return;
2391 }
2392
2393 KMFolder *srcFolder = 0;
2394 int idx;
2395 KMMsgDict::instance()->getLocation( sernum, &srcFolder, &idx );
2396 if ( srcFolder ) {
2397 KMMsgBase *msg = srcFolder->getMsgBase( idx );
2398 srcFolder->open("kmcommand");
2399 mOpenedFolders.push_back( srcFolder );
2400 addMsg( msg );
2401 }
2402 setDestFolder( findTrashFolder( srcFolder ) );
2403}
2404
2405KMFolder * KMDeleteMsgCommand::findTrashFolder( KMFolder * folder )
2406{
2407 KMFolder* trash = folder->trashFolder();
2408 if( !trash )
2409 trash = kmkernel->trashFolder();
2410 if( trash != folder )
2411 return trash;
2412 return 0;
2413}
2414
2415
2416KMUrlClickedCommand::KMUrlClickedCommand( const KURL &url, uint identity,
2417 KMReaderWin *readerWin, bool htmlPref, KMMainWidget *mainWidget )
2418 :mUrl( url ), mIdentity( identity ), mReaderWin( readerWin ),
2419 mHtmlPref( htmlPref ), mMainWidget( mainWidget )
2420{
2421}
2422
2423KMCommand::Result KMUrlClickedCommand::execute()
2424{
2425 KMMessage* msg;
2426
2427 if (mUrl.protocol() == "mailto")
2428 {
2429 msg = new KMMessage;
2430 msg->initHeader(mIdentity);
2431 msg->setCharset("utf-8");
2432 msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
2433 TQString query=mUrl.query();
2434 while (!query.isEmpty()) {
2435 TQString queryPart;
2436 int secondQuery = query.find('?',1);
2437 if (secondQuery != -1)
2438 queryPart = query.left(secondQuery);
2439 else
2440 queryPart = query;
2441 query = query.mid(queryPart.length());
2442
2443 if (queryPart.left(9) == "?subject=")
2444 msg->setSubject( KURL::decode_string(queryPart.mid(9)) );
2445 else if (queryPart.left(6) == "?body=")
2446 // It is correct to convert to latin1() as URL should not contain
2447 // anything except ascii.
2448 msg->setBody( KURL::decode_string(queryPart.mid(6)).latin1() );
2449 else if (queryPart.left(4) == "?cc=")
2450 msg->setCc( KURL::decode_string(queryPart.mid(4)) );
2451 }
2452
2453 KMail::Composer * win = KMail::makeComposer( msg, mIdentity );
2454 win->setCharset("", true);
2455 win->show();
2456 }
2457 else if ( mUrl.protocol() == "im" )
2458 {
2459 kmkernel->imProxy()->chatWithContact( mUrl.path() );
2460 }
2461 else if ((mUrl.protocol() == "http") || (mUrl.protocol() == "https") ||
2462 (mUrl.protocol() == "ftp") || (mUrl.protocol() == "file") ||
2463 (mUrl.protocol() == "ftps") || (mUrl.protocol() == "sftp" ) ||
2464 (mUrl.protocol() == "help") || (mUrl.protocol() == "vnc") ||
2465 (mUrl.protocol() == "smb") || (mUrl.protocol() == "fish") ||
2466 (mUrl.protocol() == "news"))
2467 {
2468 KPIM::BroadcastStatus::instance()->setStatusMsg( i18n("Opening URL..."));
2469 KMimeType::Ptr mime = KMimeType::findByURL( mUrl );
2470 if (mime->name() == "application/x-desktop" ||
2471 mime->name() == "application/x-executable" ||
2472 mime->name() == "application/x-msdos-program" ||
2473 mime->name() == "application/x-shellscript" )
2474 {
2475 if (KMessageBox::warningYesNo( 0, i18n( "<qt>Do you really want to execute <b>%1</b>?</qt>" )
2476 .arg( mUrl.prettyURL() ), TQString(), i18n("Execute"), KStdGuiItem::cancel() ) != KMessageBox::Yes)
2477 return Canceled;
2478 }
2479 KRun * runner = new KRun( mUrl );
2480 runner->setRunExecutables( false );
2481 }
2482 else
2483 return Failed;
2484
2485 return OK;
2486}
2487
2488KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, KMMessage *msg )
2489 : KMCommand( parent, msg ), mImplicitAttachments( true ), mEncoded( false )
2490{
2491}
2492
2493KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, const TQPtrList<KMMsgBase>& msgs )
2494 : KMCommand( parent, msgs ), mImplicitAttachments( true ), mEncoded( false )
2495{
2496}
2497
2498KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, TQPtrList<partNode>& attachments,
2499 KMMessage *msg, bool encoded )
2500 : KMCommand( parent ), mImplicitAttachments( false ), mEncoded( encoded )
2501{
2502 for ( TQPtrListIterator<partNode> it( attachments ); it.current(); ++it ) {
2503 mAttachmentMap.insert( it.current(), msg );
2504 }
2505}
2506
2507KMCommand::Result KMSaveAttachmentsCommand::execute()
2508{
2509 setEmitsCompletedItself( true );
2510 if ( mImplicitAttachments ) {
2511 TQPtrList<KMMessage> msgList = retrievedMsgs();
2512 KMMessage *msg;
2513 for ( TQPtrListIterator<KMMessage> itr( msgList );
2514 ( msg = itr.current() );
2515 ++itr ) {
2516 partNode *rootNode = partNode::fromMessage( msg );
2517 for ( partNode *child = rootNode; child;
2518 child = child->firstChild() ) {
2519 for ( partNode *node = child; node; node = node->nextSibling() ) {
2520 if ( node->type() != DwMime::kTypeMultipart )
2521 mAttachmentMap.insert( node, msg );
2522 }
2523 }
2524 }
2525 }
2526 setDeletesItself( true );
2527 // load all parts
2528 KMLoadPartsCommand *command = new KMLoadPartsCommand( mAttachmentMap );
2529 connect( command, TQ_SIGNAL( partsRetrieved() ),
2530 this, TQ_SLOT( slotSaveAll() ) );
2531 command->start();
2532
2533 return OK;
2534}
2535
2536void KMSaveAttachmentsCommand::slotSaveAll()
2537{
2538 // now that all message parts have been retrieved, remove all parts which
2539 // don't represent an attachment if they were not explicitely passed in the
2540 // c'tor
2541 if ( mImplicitAttachments ) {
2542 for ( PartNodeMessageMap::iterator it = mAttachmentMap.begin();
2543 it != mAttachmentMap.end(); ) {
2544 // only body parts which have a filename or a name parameter (except for
2545 // the root node for which name is set to the message's subject) are
2546 // considered attachments
2547 if ( it.key()->msgPart().fileName().stripWhiteSpace().isEmpty() &&
2548 ( it.key()->msgPart().name().stripWhiteSpace().isEmpty() ||
2549 !it.key()->parentNode() ) ) {
2550 PartNodeMessageMap::iterator delIt = it;
2551 ++it;
2552 mAttachmentMap.remove( delIt );
2553 }
2554 else
2555 ++it;
2556 }
2557 if ( mAttachmentMap.isEmpty() ) {
2558 KMessageBox::information( 0, i18n("Found no attachments to save.") );
2559 setResult( OK ); // The user has already been informed.
2560 emit completed( this );
2561 deleteLater();
2562 return;
2563 }
2564 }
2565
2566 KURL url, dirUrl;
2567 if ( mAttachmentMap.count() > 1 ) {
2568 // get the dir
2569 dirUrl = KDirSelectDialog::selectDirectory( TQString(), false,
2570 parentWidget(),
2571 i18n("Save Attachments To") );
2572 if ( !dirUrl.isValid() ) {
2573 setResult( Canceled );
2574 emit completed( this );
2575 deleteLater();
2576 return;
2577 }
2578
2579 // we may not get a slash-terminated url out of KDirSelectDialog
2580 dirUrl.adjustPath( 1 );
2581 }
2582 else {
2583 // only one item, get the desired filename
2584 partNode *node = mAttachmentMap.begin().key();
2585 // replace all ':' with '_' because ':' isn't allowed on FAT volumes
2586 TQString s =
2587 node->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
2588 if ( s.isEmpty() )
2589 s = node->msgPart().name().stripWhiteSpace().replace( ':', '_' );
2590 if ( s.isEmpty() )
2591 s = i18n("filename for an unnamed attachment", "attachment.1");
2592 url = KFileDialog::getSaveURL( s, TQString(), parentWidget(),
2593 TQString() );
2594 if ( url.isEmpty() ) {
2595 setResult( Canceled );
2596 emit completed( this );
2597 deleteLater();
2598 return;
2599 }
2600 }
2601
2602 TQMap< TQString, int > renameNumbering;
2603
2604 Result globalResult = OK;
2605 int unnamedAtmCount = 0;
2606 for ( PartNodeMessageMap::const_iterator it = mAttachmentMap.begin();
2607 it != mAttachmentMap.end();
2608 ++it ) {
2609 KURL curUrl;
2610 if ( !dirUrl.isEmpty() ) {
2611 curUrl = dirUrl;
2612 TQString s =
2613 it.key()->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
2614 if ( s.isEmpty() )
2615 s = it.key()->msgPart().name().stripWhiteSpace().replace( ':', '_' );
2616 if ( s.isEmpty() ) {
2617 ++unnamedAtmCount;
2618 s = i18n("filename for the %1-th unnamed attachment",
2619 "attachment.%1")
2620 .arg( unnamedAtmCount );
2621 }
2622 curUrl.setFileName( s );
2623 } else {
2624 curUrl = url;
2625 }
2626
2627 if ( !curUrl.isEmpty() ) {
2628
2629 // Rename the file if we have already saved one with the same name:
2630 // try appending a number before extension (e.g. "pic.jpg" => "pic_2.jpg")
2631 TQString origFile = curUrl.fileName();
2632 TQString file = origFile;
2633
2634 while ( renameNumbering.contains(file) ) {
2635 file = origFile;
2636 int num = renameNumbering[file] + 1;
2637 int dotIdx = file.findRev('.');
2638 file = file.insert( (dotIdx>=0) ? dotIdx : file.length(), TQString("_") + TQString::number(num) );
2639 }
2640 curUrl.setFileName(file);
2641
2642 // Increment the counter for both the old and the new filename
2643 if ( !renameNumbering.contains(origFile))
2644 renameNumbering[origFile] = 1;
2645 else
2646 renameNumbering[origFile]++;
2647
2648 if ( file != origFile ) {
2649 if ( !renameNumbering.contains(file))
2650 renameNumbering[file] = 1;
2651 else
2652 renameNumbering[file]++;
2653 }
2654
2655
2656 if ( TDEIO::NetAccess::exists( curUrl, false, parentWidget() ) ) {
2657 if ( KMessageBox::warningContinueCancel( parentWidget(),
2658 i18n( "A file named %1 already exists. Do you want to overwrite it?" )
2659 .arg( curUrl.fileName() ),
2660 i18n( "File Already Exists" ), i18n("&Overwrite") ) == KMessageBox::Cancel) {
2661 continue;
2662 }
2663 }
2664 // save
2665 const Result result = saveItem( it.key(), curUrl );
2666 if ( result != OK )
2667 globalResult = result;
2668 }
2669 }
2670 setResult( globalResult );
2671 emit completed( this );
2672 deleteLater();
2673}
2674
2675KMCommand::Result KMSaveAttachmentsCommand::saveItem( partNode *node,
2676 const KURL& url )
2677{
2678 bool bSaveEncrypted = false;
2679 bool bEncryptedParts = node->encryptionState() != KMMsgNotEncrypted;
2680 if( bEncryptedParts )
2681 if( KMessageBox::questionYesNo( parentWidget(),
2682 i18n( "The part %1 of the message is encrypted. Do you want to keep the encryption when saving?" ).
2683 arg( url.fileName() ),
2684 i18n( "KMail Question" ), i18n("Keep Encryption"), i18n("Do Not Keep") ) ==
2685 KMessageBox::Yes )
2686 bSaveEncrypted = true;
2687
2688 bool bSaveWithSig = true;
2689 if( node->signatureState() != KMMsgNotSigned )
2690 if( KMessageBox::questionYesNo( parentWidget(),
2691 i18n( "The part %1 of the message is signed. Do you want to keep the signature when saving?" ).
2692 arg( url.fileName() ),
2693 i18n( "KMail Question" ), i18n("Keep Signature"), i18n("Do Not Keep") ) !=
2694 KMessageBox::Yes )
2695 bSaveWithSig = false;
2696
2697 TQByteArray data;
2698 if ( mEncoded )
2699 {
2700 // This does not decode the Message Content-Transfer-Encoding
2701 // but saves the _original_ content of the message part
2702 data = KMail::Util::ByteArray( node->msgPart().dwBody() );
2703 }
2704 else
2705 {
2706 if( bSaveEncrypted || !bEncryptedParts) {
2707 partNode *dataNode = node;
2708 TQCString rawReplyString;
2709 bool gotRawReplyString = false;
2710 if( !bSaveWithSig ) {
2711 if( DwMime::kTypeMultipart == node->type() &&
2712 DwMime::kSubtypeSigned == node->subType() ){
2713 // carefully look for the part that is *not* the signature part:
2714 if( node->findType( DwMime::kTypeApplication,
2715 DwMime::kSubtypePgpSignature,
2716 true, false ) ){
2717 dataNode = node->findTypeNot( DwMime::kTypeApplication,
2718 DwMime::kSubtypePgpSignature,
2719 true, false );
2720 }else if( node->findType( DwMime::kTypeApplication,
2721 DwMime::kSubtypePkcs7Mime,
2722 true, false ) ){
2723 dataNode = node->findTypeNot( DwMime::kTypeApplication,
2724 DwMime::kSubtypePkcs7Mime,
2725 true, false );
2726 }else{
2727 dataNode = node->findTypeNot( DwMime::kTypeMultipart,
2728 DwMime::kSubtypeUnknown,
2729 true, false );
2730 }
2731 }else{
2732 ObjectTreeParser otp( 0, 0, false, false, false );
2733
2734 // process this node and all it's siblings and descendants
2735 dataNode->setProcessed( false, true );
2736 otp.parseObjectTree( dataNode );
2737
2738 rawReplyString = otp.rawReplyString();
2739 gotRawReplyString = true;
2740 }
2741 }
2742 TQByteArray cstr = gotRawReplyString
2743 ? rawReplyString
2744 : dataNode->msgPart().bodyDecodedBinary();
2745 data = cstr;
2746 size_t size = cstr.size();
2747 if ( dataNode->msgPart().type() == DwMime::kTypeText ) {
2748 // convert CRLF to LF before writing text attachments to disk
2749 size = KMail::Util::crlf2lf( cstr.data(), size );
2750 }
2751 data.resize( size );
2752 }
2753 }
2754 TQDataStream ds;
2755 TQFile file;
2756 KTempFile tf;
2757 tf.setAutoDelete( true );
2758 if ( url.isLocalFile() )
2759 {
2760 // save directly
2761 file.setName( url.path() );
2762 if ( !file.open( IO_WriteOnly ) )
2763 {
2764 KMessageBox::error( parentWidget(),
2765 i18n( "%2 is detailed error description",
2766 "Could not write the file %1:\n%2" )
2767 .arg( file.name() )
2768 .arg( TQString::fromLocal8Bit( strerror( errno ) ) ),
2769 i18n( "KMail Error" ) );
2770 return Failed;
2771 }
2772
2773 // #79685 by default use the umask the user defined, but let it be configurable
2774 if ( GlobalSettings::self()->disregardUmask() )
2775 fchmod( file.handle(), S_IRUSR | S_IWUSR );
2776
2777 ds.setDevice( &file );
2778 } else
2779 {
2780 // tmp file for upload
2781 ds.setDevice( tf.file() );
2782 }
2783
2784 ds.writeRawBytes( data.data(), data.size() );
2785 if ( !url.isLocalFile() )
2786 {
2787 tf.close();
2788 if ( !TDEIO::NetAccess::upload( tf.name(), url, parentWidget() ) )
2789 {
2790 KMessageBox::error( parentWidget(),
2791 i18n( "Could not write the file %1." )
2792 .arg( url.path() ),
2793 i18n( "KMail Error" ) );
2794 return Failed;
2795 }
2796 } else
2797 file.close();
2798 return OK;
2799}
2800
2801KMLoadPartsCommand::KMLoadPartsCommand( TQPtrList<partNode>& parts, KMMessage *msg )
2802 : mNeedsRetrieval( 0 )
2803{
2804 for ( TQPtrListIterator<partNode> it( parts ); it.current(); ++it ) {
2805 mPartMap.insert( it.current(), msg );
2806 }
2807}
2808
2809KMLoadPartsCommand::KMLoadPartsCommand( partNode *node, KMMessage *msg )
2810 : mNeedsRetrieval( 0 )
2811{
2812 mPartMap.insert( node, msg );
2813}
2814
2815KMLoadPartsCommand::KMLoadPartsCommand( PartNodeMessageMap& partMap )
2816 : mNeedsRetrieval( 0 ), mPartMap( partMap )
2817{
2818}
2819
2820void KMLoadPartsCommand::slotStart()
2821{
2822 for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
2823 it != mPartMap.end();
2824 ++it ) {
2825 if ( !it.key()->msgPart().isComplete() &&
2826 !it.key()->msgPart().partSpecifier().isEmpty() ) {
2827 // incomplete part, so retrieve it first
2828 ++mNeedsRetrieval;
2829 KMFolder* curFolder = it.data()->parent();
2830 if ( curFolder ) {
2831 FolderJob *job =
2832 curFolder->createJob( it.data(), FolderJob::tGetMessage,
2833 0, it.key()->msgPart().partSpecifier() );
2834 job->setCancellable( false );
2835 connect( job, TQ_SIGNAL(messageUpdated(KMMessage*, TQString)),
2836 this, TQ_SLOT(slotPartRetrieved(KMMessage*, TQString)) );
2837 job->start();
2838 } else
2839 kdWarning(5006) << "KMLoadPartsCommand - msg has no parent" << endl;
2840 }
2841 }
2842 if ( mNeedsRetrieval == 0 )
2843 execute();
2844}
2845
2846void KMLoadPartsCommand::slotPartRetrieved( KMMessage *msg,
2847 TQString partSpecifier )
2848{
2849 DwBodyPart *part =
2850 msg->findDwBodyPart( msg->getFirstDwBodyPart(), partSpecifier );
2851 if ( part ) {
2852 // update the DwBodyPart in the partNode
2853 for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
2854 it != mPartMap.end();
2855 ++it ) {
2856 if ( it.key()->dwPart()->partId() == part->partId() )
2857 it.key()->setDwPart( part );
2858 }
2859 } else
2860 kdWarning(5006) << "KMLoadPartsCommand::slotPartRetrieved - could not find bodypart!" << endl;
2861 --mNeedsRetrieval;
2862 if ( mNeedsRetrieval == 0 )
2863 execute();
2864}
2865
2866KMCommand::Result KMLoadPartsCommand::execute()
2867{
2868 emit partsRetrieved();
2869 setResult( OK );
2870 emit completed( this );
2871 deleteLater();
2872 return OK;
2873}
2874
2875KMResendMessageCommand::KMResendMessageCommand( TQWidget *parent,
2876 KMMessage *msg )
2877 :KMCommand( parent, msg )
2878{
2879}
2880
2881KMCommand::Result KMResendMessageCommand::execute()
2882{
2883 KMMessage *msg = retrievedMessage();
2884 if ( !msg || !msg->codec() ) {
2885 return Failed;
2886 }
2887 KMMessage *newMsg = new KMMessage(*msg);
2888
2889 TQStringList whiteList;
2890 whiteList << "To" << "Cc" << "Bcc" << "Subject";
2891 newMsg->sanitizeHeaders( whiteList );
2892
2893 if( newMsg->type() == DwMime::kTypeText) {
2894 newMsg->setCharset(msg->codec()->mimeName());
2895 }
2896 newMsg->setParent( 0 );
2897
2898 // make sure we have an identity set, default, if necessary
2899 newMsg->setHeaderField("X-KMail-Identity", TQString::number( newMsg->identityUoid() ));
2900 newMsg->applyIdentity( newMsg->identityUoid() );
2901
2902 KMail::Composer * win = KMail::makeComposer();
2903 win->setMsg(newMsg, false, true);
2904 win->show();
2905
2906 return OK;
2907}
2908
2909KMMailingListCommand::KMMailingListCommand( TQWidget *parent, KMFolder *folder )
2910 : KMCommand( parent ), mFolder( folder )
2911{
2912}
2913
2914KMCommand::Result KMMailingListCommand::execute()
2915{
2916 KURL::List lst = urls();
2917 TQString handler = ( mFolder->mailingList().handler() == MailingList::KMail )
2918 ? "mailto" : "https";
2919
2920 KMCommand *command = 0;
2921 for ( KURL::List::Iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
2922 if ( handler == (*itr).protocol() ) {
2923 command = new KMUrlClickedCommand( *itr, mFolder->identity(), 0, false );
2924 }
2925 }
2926 if ( !command && !lst.empty() ) {
2927 command =
2928 new KMUrlClickedCommand( lst.first(), mFolder->identity(), 0, false );
2929 }
2930 if ( command ) {
2931 connect( command, TQ_SIGNAL( completed( KMCommand * ) ),
2932 this, TQ_SLOT( commandCompleted( KMCommand * ) ) );
2933 setDeletesItself( true );
2934 setEmitsCompletedItself( true );
2935 command->start();
2936 return OK;
2937 }
2938 return Failed;
2939}
2940
2941void KMMailingListCommand::commandCompleted( KMCommand *command )
2942{
2943 setResult( command->result() );
2944 emit completed( this );
2945 deleteLater();
2946}
2947
2948KMMailingListPostCommand::KMMailingListPostCommand( TQWidget *parent, KMFolder *folder )
2949 : KMMailingListCommand( parent, folder )
2950{
2951}
2952KURL::List KMMailingListPostCommand::urls() const
2953{
2954 return mFolder->mailingList().postURLS();
2955}
2956
2957KMMailingListSubscribeCommand::KMMailingListSubscribeCommand( TQWidget *parent, KMFolder *folder )
2958 : KMMailingListCommand( parent, folder )
2959{
2960}
2961KURL::List KMMailingListSubscribeCommand::urls() const
2962{
2963 return mFolder->mailingList().subscribeURLS();
2964}
2965
2966KMMailingListUnsubscribeCommand::KMMailingListUnsubscribeCommand( TQWidget *parent, KMFolder *folder )
2967 : KMMailingListCommand( parent, folder )
2968{
2969}
2970KURL::List KMMailingListUnsubscribeCommand::urls() const
2971{
2972 return mFolder->mailingList().unsubscribeURLS();
2973}
2974
2975KMMailingListArchivesCommand::KMMailingListArchivesCommand( TQWidget *parent, KMFolder *folder )
2976 : KMMailingListCommand( parent, folder )
2977{
2978}
2979KURL::List KMMailingListArchivesCommand::urls() const
2980{
2981 return mFolder->mailingList().archiveURLS();
2982}
2983
2984KMMailingListHelpCommand::KMMailingListHelpCommand( TQWidget *parent, KMFolder *folder )
2985 : KMMailingListCommand( parent, folder )
2986{
2987}
2988KURL::List KMMailingListHelpCommand::urls() const
2989{
2990 return mFolder->mailingList().helpURLS();
2991}
2992
2993KMIMChatCommand::KMIMChatCommand( const KURL &url, KMMessage *msg )
2994 :mUrl( url ), mMessage( msg )
2995{
2996}
2997
2998KMCommand::Result KMIMChatCommand::execute()
2999{
3000 kdDebug( 5006 ) << k_funcinfo << " URL is: " << mUrl << endl;
3001 TQString addr = KMMessage::decodeMailtoUrl( mUrl.path() );
3002 // find UID for mail address
3003 TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self( true );
3004 TDEABC::AddresseeList addressees = addressBook->findByEmail( KPIM::getEmailAddress( addr ) ) ;
3005
3006 // start chat
3007 if( addressees.count() == 1 ) {
3008 kmkernel->imProxy()->chatWithContact( addressees[0].uid() );
3009 return OK;
3010 }
3011 else
3012 {
3013 kdDebug( 5006 ) << "Didn't find exactly one addressee, couldn't tell who to chat to for that email address. Count = " << addressees.count() << endl;
3014
3015 TQString apology;
3016 if ( addressees.isEmpty() )
3017 apology = i18n( "There is no Address Book entry for this email address. Add them to the Address Book and then add instant messaging addresses using your preferred messaging client." );
3018 else
3019 {
3020 apology = i18n( "More than one Address Book entry uses this email address:\n %1\n it is not possible to determine who to chat with." );
3021 TQStringList nameList;
3022 TDEABC::AddresseeList::const_iterator it = addressees.begin();
3023 TDEABC::AddresseeList::const_iterator end = addressees.end();
3024 for ( ; it != end; ++it )
3025 {
3026 nameList.append( (*it).realName() );
3027 }
3028 TQString names = nameList.join( TQString::fromLatin1( ",\n" ) );
3029 apology = apology.arg( names );
3030 }
3031
3032 KMessageBox::sorry( parentWidget(), apology );
3033 return Failed;
3034 }
3035}
3036
3037KMHandleAttachmentCommand::KMHandleAttachmentCommand( partNode* node,
3038 KMMessage* msg, int atmId, const TQString& atmName,
3039 AttachmentAction action, KService::Ptr offer, TQWidget* parent )
3040: KMCommand( parent ), mNode( node ), mMsg( msg ), mAtmId( atmId ), mAtmName( atmName ),
3041 mAction( action ), mOffer( offer ), mJob( 0 )
3042{
3043}
3044
3045void KMHandleAttachmentCommand::slotStart()
3046{
3047 if ( !mNode->msgPart().isComplete() )
3048 {
3049 // load the part
3050 kdDebug(5006) << "load part" << endl;
3051 KMLoadPartsCommand *command = new KMLoadPartsCommand( mNode, mMsg );
3052 connect( command, TQ_SIGNAL( partsRetrieved() ),
3053 this, TQ_SLOT( slotPartComplete() ) );
3054 command->start();
3055 } else
3056 {
3057 execute();
3058 }
3059}
3060
3061void KMHandleAttachmentCommand::slotPartComplete()
3062{
3063 execute();
3064}
3065
3066KMCommand::Result KMHandleAttachmentCommand::execute()
3067{
3068 switch( mAction )
3069 {
3070 case Open:
3071 atmOpen();
3072 break;
3073 case OpenWith:
3074 atmOpenWith();
3075 break;
3076 case View:
3077 atmView();
3078 break;
3079 case Save:
3080 atmSave();
3081 break;
3082 case Properties:
3083 atmProperties();
3084 break;
3085 case ChiasmusEncrypt:
3086 atmEncryptWithChiasmus();
3087 return Undefined;
3088 break;
3089 default:
3090 kdDebug(5006) << "unknown action " << mAction << endl;
3091 break;
3092 }
3093 setResult( OK );
3094 emit completed( this );
3095 deleteLater();
3096 return OK;
3097}
3098
3099TQString KMHandleAttachmentCommand::createAtmFileLink() const
3100{
3101 TQFileInfo atmFileInfo( mAtmName );
3102
3103 if ( atmFileInfo.size() == 0 )
3104 {
3105 kdDebug(5006) << k_funcinfo << "rewriting attachment" << endl;
3106 // there is something wrong so write the file again
3107 TQByteArray data = mNode->msgPart().bodyDecodedBinary();
3108 size_t size = data.size();
3109 if ( mNode->msgPart().type() == DwMime::kTypeText && size) {
3110 // convert CRLF to LF before writing text attachments to disk
3111 size = KMail::Util::crlf2lf( data.data(), size );
3112 }
3113 KPIM::kBytesToFile( data.data(), size, mAtmName, false, false, false );
3114 }
3115
3116 KTempFile *linkFile = new KTempFile( locateLocal("tmp", atmFileInfo.fileName() +"_["),
3117 "]."+ atmFileInfo.extension() );
3118
3119 linkFile->setAutoDelete(true);
3120 TQString linkName = linkFile->name();
3121 delete linkFile;
3122
3123 if ( ::link(TQFile::encodeName( mAtmName ), TQFile::encodeName( linkName )) == 0 ) {
3124 return linkName; // success
3125 }
3126 return TQString();
3127}
3128
3129KService::Ptr KMHandleAttachmentCommand::getServiceOffer()
3130{
3131 KMMessagePart& msgPart = mNode->msgPart();
3132 const TQString contentTypeStr =
3133 ( msgPart.typeStr() + '/' + msgPart.subtypeStr() ).lower();
3134
3135 if ( contentTypeStr == "text/x-vcard" ) {
3136 atmView();
3137 return 0;
3138 }
3139 // determine the MIME type of the attachment
3140 KMimeType::Ptr mimetype;
3141 // prefer the value of the Content-Type header
3142 mimetype = KMimeType::mimeType( contentTypeStr );
3143 if ( mimetype->name() == "application/octet-stream" ) {
3144 // consider the filename if Content-Type is application/octet-stream
3145 mimetype = KMimeType::findByPath( mAtmName, 0, true /* no disk access */ );
3146 }
3147 if ( ( mimetype->name() == "application/octet-stream" )
3148 && msgPart.isComplete() ) {
3149 // consider the attachment's contents if neither the Content-Type header
3150 // nor the filename give us a clue
3151 mimetype = KMimeType::findByFileContent( mAtmName );
3152 }
3153 return KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
3154}
3155
3156void KMHandleAttachmentCommand::atmOpen()
3157{
3158 if ( !mOffer )
3159 mOffer = getServiceOffer();
3160 if ( !mOffer ) {
3161 kdDebug(5006) << k_funcinfo << "got no offer" << endl;
3162 return;
3163 }
3164
3165 KURL::List lst;
3166 KURL url;
3167 bool autoDelete = true;
3168 TQString fname = createAtmFileLink();
3169
3170 if ( fname.isNull() ) {
3171 autoDelete = false;
3172 fname = mAtmName;
3173 }
3174
3175 url.setPath( fname );
3176 lst.append( url );
3177 if ( (KRun::run( *mOffer, lst, autoDelete ) <= 0) && autoDelete ) {
3178 TQFile::remove(url.path());
3179 }
3180}
3181
3182void KMHandleAttachmentCommand::atmOpenWith()
3183{
3184 KURL::List lst;
3185 KURL url;
3186 bool autoDelete = true;
3187 TQString fname = createAtmFileLink();
3188
3189 if ( fname.isNull() ) {
3190 autoDelete = false;
3191 fname = mAtmName;
3192 }
3193
3194 url.setPath( fname );
3195 lst.append( url );
3196 if ( (! KRun::displayOpenWithDialog(lst, autoDelete)) && autoDelete ) {
3197 TQFile::remove( url.path() );
3198 }
3199}
3200
3201void KMHandleAttachmentCommand::atmView()
3202{
3203 // we do not handle this ourself
3204 emit showAttachment( mAtmId, mAtmName );
3205}
3206
3207void KMHandleAttachmentCommand::atmSave()
3208{
3209 TQPtrList<partNode> parts;
3210 parts.append( mNode );
3211 // save, do not leave encoded
3212 KMSaveAttachmentsCommand *command =
3213 new KMSaveAttachmentsCommand( parentWidget(), parts, mMsg, false );
3214 command->start();
3215}
3216
3217void KMHandleAttachmentCommand::atmProperties()
3218{
3219 KMMsgPartDialogCompat dlg( parentWidget() , 0, true );
3220 KMMessagePart& msgPart = mNode->msgPart();
3221 dlg.setMsgPart( &msgPart );
3222 dlg.exec();
3223}
3224
3225void KMHandleAttachmentCommand::atmEncryptWithChiasmus()
3226{
3227 const partNode * node = mNode;
3228 Q_ASSERT( node );
3229 if ( !node )
3230 return;
3231
3232 // FIXME: better detection of mimetype??
3233 if ( !mAtmName.endsWith( ".xia", false ) )
3234 return;
3235
3236 const Kleo::CryptoBackend::Protocol * chiasmus =
3237 Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
3238 Q_ASSERT( chiasmus );
3239 if ( !chiasmus )
3240 return;
3241
3242 const STD_NAMESPACE_PREFIX unique_ptr<Kleo::SpecialJob> listjob( chiasmus->specialJob( "x-obtain-keys", TQStringVariantMap() ) );
3243 if ( !listjob ) {
3244 const TQString msg = i18n( "Chiasmus backend does not offer the "
3245 "\"x-obtain-keys\" function. Please report this bug." );
3246 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3247 return;
3248 }
3249
3250 if ( listjob->exec() ) {
3251 listjob->showErrorDialog( parentWidget(), i18n( "Chiasmus Backend Error" ) );
3252 return;
3253 }
3254
3255 const TQVariant result = listjob->property( "result" );
3256 if ( result.type() != TQVariant::StringList ) {
3257 const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
3258 "The \"x-obtain-keys\" function did not return a "
3259 "string list. Please report this bug." );
3260 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3261 return;
3262 }
3263
3264 const TQStringList keys = result.toStringList();
3265 if ( keys.empty() ) {
3266 const TQString msg = i18n( "No keys have been found. Please check that a "
3267 "valid key path has been set in the Chiasmus "
3268 "configuration." );
3269 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3270 return;
3271 }
3272
3273 ChiasmusKeySelector selectorDlg( parentWidget(), i18n( "Chiasmus Decryption Key Selection" ),
3274 keys, GlobalSettings::chiasmusDecryptionKey(),
3275 GlobalSettings::chiasmusDecryptionOptions() );
3276 if ( selectorDlg.exec() != TQDialog::Accepted )
3277 return;
3278
3279 GlobalSettings::setChiasmusDecryptionOptions( selectorDlg.options() );
3280 GlobalSettings::setChiasmusDecryptionKey( selectorDlg.key() );
3281 assert( !GlobalSettings::chiasmusDecryptionKey().isEmpty() );
3282
3283 Kleo::SpecialJob * job = chiasmus->specialJob( "x-decrypt", TQStringVariantMap() );
3284 if ( !job ) {
3285 const TQString msg = i18n( "Chiasmus backend does not offer the "
3286 "\"x-decrypt\" function. Please report this bug." );
3287 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3288 return;
3289 }
3290
3291 const TQByteArray input = node->msgPart().bodyDecodedBinary();
3292
3293 if ( !job->setProperty( "key", GlobalSettings::chiasmusDecryptionKey() ) ||
3294 !job->setProperty( "options", GlobalSettings::chiasmusDecryptionOptions() ) ||
3295 !job->setProperty( "input", input ) ) {
3296 const TQString msg = i18n( "The \"x-decrypt\" function does not accept "
3297 "the expected parameters. Please report this bug." );
3298 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3299 return;
3300 }
3301
3302 setDeletesItself( true ); // the job below is async, we have to cleanup ourselves
3303 if ( job->start() ) {
3304 job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
3305 return;
3306 }
3307
3308 mJob = job;
3309 connect( job, TQ_SIGNAL(result(const GpgME::Error&,const TQVariant&)),
3310 this, TQ_SLOT(slotAtmDecryptWithChiasmusResult(const GpgME::Error&,const TQVariant&)) );
3311}
3312
3313static const TQString chomp( const TQString & base, const TQString & suffix, bool cs ) {
3314 return base.endsWith( suffix, cs ) ? base.left( base.length() - suffix.length() ) : base ;
3315}
3316
3317void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusResult( const GpgME::Error & err, const TQVariant & result )
3318{
3319 LaterDeleterWithCommandCompletion d( this );
3320 if ( !mJob )
3321 return;
3322 Q_ASSERT( mJob == sender() );
3323 if ( mJob != sender() )
3324 return;
3325 Kleo::Job * job = mJob;
3326 mJob = 0;
3327 if ( err.isCanceled() )
3328 return;
3329 if ( err ) {
3330 job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
3331 return;
3332 }
3333
3334 if ( result.type() != TQVariant::ByteArray ) {
3335 const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
3336 "The \"x-decrypt\" function did not return a "
3337 "byte array. Please report this bug." );
3338 KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3339 return;
3340 }
3341
3342 const KURL url = KFileDialog::getSaveURL( chomp( mAtmName, ".xia", false ), TQString(), parentWidget() );
3343 if ( url.isEmpty() )
3344 return;
3345
3346 bool overwrite = KMail::Util::checkOverwrite( url, parentWidget() );
3347 if ( !overwrite )
3348 return;
3349
3350 d.setDisabled( true ); // we got this far, don't delete yet
3351 TDEIO::Job * uploadJob = TDEIO::storedPut( result.toByteArray(), url, -1, overwrite, false /*resume*/ );
3352 uploadJob->setWindow( parentWidget() );
3353 connect( uploadJob, TQ_SIGNAL(result(TDEIO::Job*)),
3354 this, TQ_SLOT(slotAtmDecryptWithChiasmusUploadResult(TDEIO::Job*)) );
3355}
3356
3357void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusUploadResult( TDEIO::Job * job )
3358{
3359 if ( job->error() )
3360 job->showErrorDialog();
3361 LaterDeleterWithCommandCompletion d( this );
3362 d.setResult( OK );
3363}
3364
3365
3366AttachmentModifyCommand::AttachmentModifyCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
3367 KMCommand( parent, msg ),
3368 mPartIndex( node->nodeId() ),
3369 mSernum( 0 )
3370{
3371}
3372
3373AttachmentModifyCommand::AttachmentModifyCommand( int nodeId, KMMessage *msg, TQWidget *parent )
3374 : KMCommand( parent, msg ),
3375 mPartIndex( nodeId ),
3376 mSernum( 0 )
3377{
3378}
3379
3380AttachmentModifyCommand::~ AttachmentModifyCommand()
3381{
3382}
3383
3384KMCommand::Result AttachmentModifyCommand::execute()
3385{
3386 KMMessage *msg = retrievedMessage();
3387 if ( !msg )
3388 return Failed;
3389 mSernum = msg->getMsgSerNum();
3390
3391 mFolder = msg->parent();
3392 if ( !mFolder || !mFolder->storage() )
3393 return Failed;
3394
3395 Result res = doAttachmentModify();
3396 if ( res != OK )
3397 return res;
3398
3399 setEmitsCompletedItself( true );
3400 setDeletesItself( true );
3401 return OK;
3402}
3403
3404void AttachmentModifyCommand::storeChangedMessage(KMMessage * msg)
3405{
3406 if ( !mFolder || !mFolder->storage() ) {
3407 kdWarning(5006) << k_funcinfo << "We lost the folder!" << endl;
3408 setResult( Failed );
3409 emit completed( this );
3410 deleteLater();
3411 }
3412 int res = mFolder->addMsg( msg ) != 0;
3413 if ( mFolder->folderType() == KMFolderTypeImap ) {
3414 KMFolderImap *f = static_cast<KMFolderImap*>( mFolder->storage() );
3415 connect( f, TQ_SIGNAL(folderComplete(KMFolderImap*,bool)),
3416 TQ_SLOT(messageStoreResult(KMFolderImap*,bool)) );
3417 } else {
3418 messageStoreResult( 0, res == 0 );
3419 }
3420}
3421
3422void AttachmentModifyCommand::messageStoreResult(KMFolderImap* folder, bool success )
3423{
3424 Q_UNUSED( folder );
3425 if ( success ) {
3426 KMCommand *delCmd = new KMDeleteMsgCommand( mSernum );
3427 connect( delCmd, TQ_SIGNAL(completed(KMCommand*)), TQ_SLOT(messageDeleteResult(KMCommand*)) );
3428 delCmd->start();
3429 return;
3430 }
3431 kdWarning(5006) << k_funcinfo << "Adding modified message failed." << endl;
3432 setResult( Failed );
3433 emit completed( this );
3434 deleteLater();
3435}
3436
3437void AttachmentModifyCommand::messageDeleteResult(KMCommand * cmd)
3438{
3439 setResult( cmd->result() );
3440 emit completed( this );
3441 deleteLater();
3442}
3443
3444KMDeleteAttachmentCommand::KMDeleteAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
3445 AttachmentModifyCommand( node, msg, parent )
3446{
3447 kdDebug(5006) << k_funcinfo << endl;
3448}
3449
3450KMDeleteAttachmentCommand::KMDeleteAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent )
3451 : AttachmentModifyCommand( nodeId, msg, parent )
3452{
3453 kdDebug(5006) << k_funcinfo << endl;
3454}
3455
3456KMDeleteAttachmentCommand::~KMDeleteAttachmentCommand()
3457{
3458 kdDebug(5006) << k_funcinfo << endl;
3459}
3460
3461KMCommand::Result KMDeleteAttachmentCommand::doAttachmentModify()
3462{
3463 KMMessage *msg = retrievedMessage();
3464 if ( !msg || !msg->deleteBodyPart( mPartIndex ) )
3465 return Failed;
3466
3467 KMMessage *newMsg = new KMMessage();
3468 newMsg->fromDwString( msg->asDwString() );
3469 newMsg->setStatus( msg->status() );
3470
3471 storeChangedMessage( newMsg );
3472 return OK;
3473}
3474
3475
3476KMEditAttachmentCommand::KMEditAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
3477 AttachmentModifyCommand( node, msg, parent )
3478{
3479 kdDebug(5006) << k_funcinfo << endl;
3480 mTempFile.setAutoDelete( true );
3481}
3482
3483KMEditAttachmentCommand::KMEditAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent )
3484 : AttachmentModifyCommand( nodeId, msg, parent )
3485{
3486 kdDebug(5006) << k_funcinfo << endl;
3487 mTempFile.setAutoDelete( true );
3488}
3489
3490KMEditAttachmentCommand::~ KMEditAttachmentCommand()
3491{
3492}
3493
3494KMCommand::Result KMEditAttachmentCommand::doAttachmentModify()
3495{
3496 KMMessage *msg = retrievedMessage();
3497 if ( !msg )
3498 return Failed;
3499
3500 KMMessagePart part;
3501 DwBodyPart *dwpart = msg->findPart( mPartIndex );
3502 if ( !dwpart )
3503 return Failed;
3504 KMMessage::bodyPart( dwpart, &part, true );
3505 if ( !part.isComplete() )
3506 return Failed;
3507
3508 if( !dynamic_cast<DwBody*>( dwpart->Parent() ) )
3509 return Failed;
3510
3511 mTempFile.file()->writeBlock( part.bodyDecodedBinary() );
3512 mTempFile.file()->flush();
3513
3514 KMail::EditorWatcher *watcher =
3515 new KMail::EditorWatcher( KURL( mTempFile.file()->name() ),
3516 part.typeStr() + "/" + part.subtypeStr(),
3517 false, this, parentWidget() );
3518 connect( watcher, TQ_SIGNAL(editDone(KMail::EditorWatcher*)), TQ_SLOT(editDone(KMail::EditorWatcher*)) );
3519 if ( !watcher->start() )
3520 return Failed;
3521 setEmitsCompletedItself( true );
3522 setDeletesItself( true );
3523 return OK;
3524}
3525
3526void KMEditAttachmentCommand::editDone(KMail::EditorWatcher * watcher)
3527{
3528 kdDebug(5006) << k_funcinfo << endl;
3529 // anything changed?
3530 if ( !watcher->fileChanged() ) {
3531 kdDebug(5006) << k_funcinfo << "File has not been changed" << endl;
3532 setResult( Canceled );
3533 emit completed( this );
3534 deleteLater();
3535 }
3536
3537 mTempFile.file()->reset();
3538 TQByteArray data = mTempFile.file()->readAll();
3539
3540 // build the new message
3541 KMMessage *msg = retrievedMessage();
3542 KMMessagePart part;
3543 DwBodyPart *dwpart = msg->findPart( mPartIndex );
3544 KMMessage::bodyPart( dwpart, &part, true );
3545
3546 DwBody *parentNode = dynamic_cast<DwBody*>( dwpart->Parent() );
3547 assert( parentNode );
3548 parentNode->RemoveBodyPart( dwpart );
3549
3550 KMMessagePart att;
3551 att.duplicate( part );
3552 att.setBodyEncodedBinary( data );
3553
3554 DwBodyPart* newDwPart = msg->createDWBodyPart( &att );
3555 parentNode->AddBodyPart( newDwPart );
3556 msg->getTopLevelPart()->Assemble();
3557
3558 KMMessage *newMsg = new KMMessage();
3559 newMsg->fromDwString( msg->asDwString() );
3560 newMsg->setStatus( msg->status() );
3561
3562 storeChangedMessage( newMsg );
3563}
3564
3565
3566CreateTodoCommand::CreateTodoCommand(TQWidget * parent, KMMessage * msg)
3567 : KMCommand( parent, msg )
3568{
3569}
3570
3571KMCommand::Result CreateTodoCommand::execute()
3572{
3573 KMMessage *msg = retrievedMessage();
3574 if ( !msg || !msg->codec() ) {
3575 return Failed;
3576 }
3577
3578 KMail::KorgHelper::ensureRunning();
3579
3580 TQString txt = i18n("From: %1\nTo: %2\nSubject: %3").arg( msg->from() )
3581 .arg( msg->to() ).arg( msg->subject() );
3582
3583 KTempFile tf;
3584 tf.setAutoDelete( true );
3585 TQString uri = "kmail:" + TQString::number( msg->getMsgSerNum() ) + "/" + msg->msgId();
3586 tf.file()->writeBlock( msg->asDwString().c_str(), msg->asDwString().length() );
3587 tf.close();
3588
3589 KCalendarIface_stub *iface = new KCalendarIface_stub( tdeApp->dcopClient(), "korganizer", "CalendarIface" );
3590 iface->openTodoEditor( i18n("Mail: %1").arg( msg->subject() ), txt, uri,
3591 tf.name(), TQStringList(), "message/rfc822", true );
3592 delete iface;
3593
3594 return OK;
3595}
3596
3597#include "kmcommands.moc"
Base class for commands modifying attachements of existing messages.
Definition: kmcommands.h:1092
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
Definition: kcursorsaver.h:14
static void sendMDN(KMMessage *msg, KMime::MDN::DispositionType d, const TQValueList< KMime::MDN::DispositionModifier > &m=TQValueList< KMime::MDN::DispositionModifier >())
Automates the sending of MDNs from filter actions.
KMail list that manages the contents of one directory that may contain folders and/or other directori...
Definition: kmfolderdir.h:16
virtual TQString prettyURL() const
URL of the node for visualization purposes.
Mail folder.
Definition: kmfolder.h:69
bool isOpened() const
Test if folder is opened.
Definition: kmfolder.cpp:500
KMFolder * trashFolder() const
If this folder has a special trash folder set, return it.
Definition: kmfolder.cpp:821
virtual TQString prettyURL() const
URL of the node for visualization purposes.
Definition: kmfolder.cpp:593
virtual TQString label() const
Returns the label of the folder for visualization.
Definition: kmfolder.cpp:581
KMMsgInfo * unGetMsg(int idx)
Replace KMMessage with KMMsgInfo and delete KMMessage
Definition: kmfolder.cpp:326
FolderJob * createJob(KMMessage *msg, FolderJob::JobType jt=FolderJob::tGetMessage, KMFolder *folder=0, TQString partSpecifier=TQString(), const AttachmentStrategy *as=0) const
These methods create respective FolderJob (You should derive FolderJob for each derived KMFolder).
Definition: kmfolder.cpp:346
bool isMessage(int idx)
Checks if the message is already "gotten" with getMsg.
Definition: kmfolder.cpp:331
KMMessage * take(int idx)
Detach message from this folder.
Definition: kmfolder.cpp:380
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
const KMMsgBase * getMsgBase(int idx) const
Provides access to the basic message fields that are also stored in the index.
Definition: kmfolder.cpp:360
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
void setStatus(int idx, KMMsgStatus status, bool toggle=false)
Set the status of the message at index idx to status.
Definition: kmfolder.cpp:831
int open(const char *owner)
Open folder for access.
Definition: kmfolder.cpp:479
bool noContent() const
Returns, if the folder can't contain mails, but only subfolder.
Definition: kmfolder.cpp:301
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
int find(const KMMsgBase *msg) const
Returns the index of the given message or -1 if not found.
Definition: kmfolder.cpp:435
bool isReadOnly() const
Is the folder read-only?
Definition: kmfolder.cpp:561
The widget that shows the contents of folders.
Definition: kmheaders.h:47
This is a Mime Message.
Definition: kmmessage.h:68
uint identityUoid() const
Definition: kmmessage.cpp:1727
void link(const KMMessage *aMsg, KMMsgStatus aStatus)
Links this message to aMsg, setting link type to aStatus.
Definition: kmmessage.cpp:4190
void setBody(const TQCString &aStr)
Set the message body.
Definition: kmmessage.cpp:2774
DwBodyPart * getFirstDwBodyPart() const
Get the 1st DwBodyPart.
Definition: kmmessage.cpp:2848
void setReadyToShow(bool v)
Set if the message is ready to be shown.
Definition: kmmessage.h:874
static void bodyPart(DwBodyPart *aDwBodyPart, KMMessagePart *aPart, bool withBody=true)
Fill the KMMessagePart structure for a given DwBodyPart.
Definition: kmmessage.cpp:3108
size_t msgSizeServer() const
Get/set size on server.
Definition: kmmessage.cpp:2212
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
Definition: kmmessage.cpp:243
TQCString body() const
Get the message body.
Definition: kmmessage.cpp:2570
TQString msgId() const
Get or set the 'Message-Id' header field.
Definition: kmmessage.cpp:2182
TQString from() const
Get or set the 'From' header field.
Definition: kmmessage.cpp:2015
TQCString charset() const
Get the message charset.
Definition: kmmessage.cpp:4098
void setAutomaticFields(bool isMultipart=false)
Set fields that are either automatically set (Message-id) or that do not change from one message to a...
Definition: kmmessage.cpp:1777
void setCharset(const TQCString &charset, DwEntity *entity=0)
Sets the charset of the message or a subpart of the message.
Definition: kmmessage.cpp:4114
void setStatus(const KMMsgStatus status, int idx=-1)
Set status and mark dirty.
Definition: kmmessage.cpp:4153
bool deleteBodyPart(int partIndex)
Delete a body part with the specified part index.
Definition: kmmessage.cpp:3181
TQString to() const
Get or set the 'To' header field.
Definition: kmmessage.cpp:1894
TQString subject() const
Get or set the 'Subject' header field.
Definition: kmmessage.cpp:2049
KMMessage * createForward(const TQString &tmpl=TQString())
Create a new message that is a forward of this message, filling all required header fields with the p...
Definition: kmmessage.cpp:1229
void removeHeaderField(const TQCString &name)
Remove header field with given name.
Definition: kmmessage.cpp:2317
void fromDwString(const DwString &str, bool setStatus=false)
Parse the string and create this message from it.
Definition: kmmessage.cpp:402
KMMessage * createReply(KMail::ReplyStrategy replyStrategy=KMail::ReplySmart, TQString selection=TQString(), bool noQuote=false, bool allowDecryption=true, const TQString &tmpl=TQString(), const TQString &originatingAccount=TQString())
Create a new message that is a reply to this message, filling all required header fields with the pro...
Definition: kmmessage.cpp:863
TQCString asString() const
Return the entire message contents as a string.
Definition: kmmessage.cpp:314
KMMessage * createRedirect(const TQString &toStr)
Create a new message that is a redirect to this message, filling all required header fields with the ...
Definition: kmmessage.cpp:1131
KMMsgBase & toMsgBase()
Get KMMsgBase for this object.
Definition: kmmessage.h:114
void removePrivateHeaderFields()
Remove all private header fields: Status: and X-KMail-
Definition: kmmessage.cpp:335
const DwString & asDwString() const
Return the entire message contents in the DwString.
Definition: kmmessage.cpp:292
bool transferInProgress() const
Return, if the message should not be deleted.
Definition: kmmessage.cpp:236
void sanitizeHeaders(const TQStringList &whiteList=TQStringList())
Remove all headers but the content description ones, and those in the white list.
Definition: kmmessage.cpp:1210
static TQString decodeMailtoUrl(const TQString &url)
Decodes a mailto URL.
Definition: kmmessage.cpp:3473
const TQTextCodec * codec() const
Get a TQTextCodec suitable for this message part.
Definition: kmmessage.cpp:4453
void setComplete(bool v)
Set if the message is a complete message.
Definition: kmmessage.h:869
KMMsgStatus status() const
Status of the message.
Definition: kmmessage.h:830
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
Definition: kmmessage.cpp:2289
void applyIdentity(uint id)
Set the from, to, cc, bcc, encrytion etc headers as specified in the given identity.
Definition: kmmessage.cpp:1662
TQCString mboxMessageSeparator()
Returns an mbox message separator line for this message, i.e.
Definition: kmmessage.cpp:4481
void initFromMessage(const KMMessage *msg, bool idHeaders=true)
Initialize headers fields according to the identity and the transport header of the given original me...
Definition: kmmessage.cpp:1742
bool isComplete() const
Return true if the complete message is available without referring to the backing store.
Definition: kmmessage.h:867
TQString headerAsString() const
Return header as string.
Definition: kmmessage.cpp:378
void initHeader(uint identity=0)
Initialize header fields.
Definition: kmmessage.cpp:1715
void setHeaderField(const TQCString &name, const TQString &value, HeaderFieldType type=Unstructured, bool prepend=false)
Set the header field with the given name to the given value.
Definition: kmmessage.cpp:2339
DwBodyPart * findDwBodyPart(int type, int subtype) const
Return the first DwBodyPart matching a given Content-Type or zero, if no found.
Definition: kmmessage.cpp:2935
DwBodyPart * createDWBodyPart(const KMMessagePart *aPart)
Compose a DwBodyPart (needed for adding a part to the message).
Definition: kmmessage.cpp:3218
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
Definition: kmmsgdict.cpp:319
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Definition: kmmsgdict.cpp:167
The attachment dialog with convenience backward compatible methods.
Definition: kmmsgpartdlg.h:141
This class implements a "reader window", that is a window used for reading or viewing messages.
Definition: kmreaderwin.h:75
Starts an editor for the given URL and emits an signal when editing has been finished.
Definition: editorwatcher.h:39
Visual representation of a member of the set of displayables (mails in the current folder).
Definition: headeritem.h:164
This class encapsulates the visual appearance of message headers.
Definition: headerstyle.h:51
KMail message redirection dialog.
Window class for secondary KMail window like the composer window and the separate message window.
A LaterDeleter is intended to be used with the RAII ( Resource Acquisition is Initialization ) paradi...
Definition: util.h:180
The TemplateParser transforms a message with a given template.
void append(TQByteArray &that, const TQByteArray &str)
Append a bytearray to a bytearray.
Definition: util.cpp:144
TQByteArray ByteArray(const DwString &str)
Construct a TQByteArray from a DwString.
Definition: util.cpp:122
size_t crlf2lf(char *str, const size_t strLen)
Convert all sequences of "\r\n" (carriage return followed by a line feed) to a single "\n" (line feed...
Definition: util.cpp:44
folderdiaquotatab.h
Definition: aboutdata.cpp:40