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 <kstandarddirs.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"
85 using 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"
105 using KMail::ObjectTreeParser;
106 using KMail::FolderJob;
107 #include "chiasmuskeyselector.h"
108 #include "mailsourceviewer.h"
109 using 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"
127 using KPIM::ProgressManager;
128 using KPIM::ProgressItem;
129 #include <kmime_mdn.h>
130 using 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 
140 class LaterDeleterWithCommandCompletion : public KMail::Util::LaterDeleter
141 {
142 public:
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; }
154 private:
155  KMCommand::Result m_result;
156 };
157 
158 
159 KMCommand::KMCommand( TQWidget *parent )
160  : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
161  mEmitsCompletedItself( false ), mParent( parent )
162 {
163 }
164 
165 KMCommand::KMCommand( TQWidget *parent, const TQPtrList<KMMsgBase> &msgList )
166  : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
167  mEmitsCompletedItself( false ), mParent( parent ), mMsgList( msgList )
168 {
169 }
170 
171 KMCommand::KMCommand( TQWidget *parent, KMMsgBase *msgBase )
172  : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
173  mEmitsCompletedItself( false ), mParent( parent )
174 {
175  mMsgList.append( msgBase );
176 }
177 
178 KMCommand::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 
186 KMCommand::~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 
196 KMCommand::Result KMCommand::result()
197 {
198  if ( mResult == Undefined )
199  kdDebug(5006) << k_funcinfo << "mResult is Undefined" << endl;
200  return mResult;
201 }
202 
203 void KMCommand::start()
204 {
205  TQTimer::singleShot( 0, this, TQ_SLOT( slotStart() ) );
206 }
207 
208 
209 const TQPtrList<KMMessage> KMCommand::retrievedMsgs() const
210 {
211  return mRetrievedMsgs;
212 }
213 
214 KMMessage *KMCommand::retrievedMessage() const
215 {
216  return mRetrievedMsgs.getFirst();
217 }
218 
219 TQWidget *KMCommand::parentWidget() const
220 {
221  return mParent;
222 }
223 
224 int KMCommand::mCountJobs = 0;
225 
226 void 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 
262 void 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 
284 void 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 
373 void 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 
384 void KMCommand::slotProgress( unsigned long done, unsigned long /*total*/ )
385 {
386  mProgressDialog->progressBar()->setProgress( done );
387 }
388 
389 void 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 
418 void 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 
451 void KMCommand::keepFolderOpen( KMFolder *folder )
452 {
453  folder->open( "kmcommand" );
454  mFolders.append( folder );
455 }
456 
457 KMMailtoComposeCommand::KMMailtoComposeCommand( const KURL &url,
458  KMMessage *msg )
459  :mUrl( url ), mMessage( msg )
460 {
461 }
462 
463 KMCommand::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 
484 KMMailtoReplyCommand::KMMailtoReplyCommand( TQWidget *parent,
485  const KURL &url, KMMessage *msg, const TQString &selection )
486  :KMCommand( parent, msg ), mUrl( url ), mSelection( selection )
487 {
488 }
489 
490 KMCommand::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 
509 KMMailtoForwardCommand::KMMailtoForwardCommand( TQWidget *parent,
510  const KURL &url, KMMessage *msg )
511  :KMCommand( parent, msg ), mUrl( url )
512 {
513 }
514 
515 KMCommand::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 
533 KMAddBookmarksCommand::KMAddBookmarksCommand( const KURL &url, TQWidget *parent )
534  : KMCommand( parent ), mUrl( url )
535 {
536 }
537 
538 KMCommand::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 
552 KMMailtoAddAddrBookCommand::KMMailtoAddAddrBookCommand( const KURL &url,
553  TQWidget *parent )
554  : KMCommand( parent ), mUrl( url )
555 {
556 }
557 
558 KMCommand::Result KMMailtoAddAddrBookCommand::execute()
559 {
560  KAddrBookExternal::addEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
561  parentWidget() );
562 
563  return OK;
564 }
565 
566 
567 KMMailtoOpenAddrBookCommand::KMMailtoOpenAddrBookCommand( const KURL &url,
568  TQWidget *parent )
569  : KMCommand( parent ), mUrl( url )
570 {
571 }
572 
573 KMCommand::Result KMMailtoOpenAddrBookCommand::execute()
574 {
575  KAddrBookExternal::openEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
576  parentWidget() );
577 
578  return OK;
579 }
580 
581 
582 KMUrlCopyCommand::KMUrlCopyCommand( const KURL &url, KMMainWidget *mainWidget )
583  :mUrl( url ), mMainWidget( mainWidget )
584 {
585 }
586 
587 KMCommand::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 
612 KMUrlOpenCommand::KMUrlOpenCommand( const KURL &url, KMReaderWin *readerWin )
613  :mUrl( url ), mReaderWin( readerWin )
614 {
615 }
616 
617 KMCommand::Result KMUrlOpenCommand::execute()
618 {
619  if ( !mUrl.isEmpty() )
620  mReaderWin->slotUrlOpen( mUrl, KParts::URLArgs() );
621 
622  return OK;
623 }
624 
625 
626 KMUrlSaveCommand::KMUrlSaveCommand( const KURL &url, TQWidget *parent )
627  : KMCommand( parent ), mUrl( url )
628 {
629 }
630 
631 KMCommand::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 
653 void 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 
667 KMEditMsgCommand::KMEditMsgCommand( TQWidget *parent, KMMessage *msg )
668  :KMCommand( parent, msg )
669 {
670 }
671 
672 KMCommand::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 
696 KMUseTemplateCommand::KMUseTemplateCommand( TQWidget *parent, KMMessage *msg )
697  :KMCommand( parent, msg )
698 {
699 }
700 
701 KMCommand::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 
724 KMShowMsgSrcCommand::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 
732 KMCommand::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 
764 static 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 
785 KMSaveMsgCommand::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 
809 KMSaveMsgCommand::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 
837 KURL KMSaveMsgCommand::url()
838 {
839  return mUrl;
840 }
841 
842 KMCommand::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 
856 void 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 
924 void 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 
958 void 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 
996 KMOpenMsgCommand::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 
1005 KMCommand::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 
1025 void KMOpenMsgCommand::slotDataArrived( TDEIO::Job *, const TQByteArray & data )
1026 {
1027  if ( data.isEmpty() )
1028  return;
1029 
1030  mMsgString.append( data.data(), data.size() );
1031 }
1032 
1033 void 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
1105 KMReplyToCommand::KMReplyToCommand( TQWidget *parent, KMMessage *msg,
1106  const TQString &selection )
1107  : KMCommand( parent, msg ), mSelection( selection )
1108 {
1109 }
1110 
1111 KMCommand::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 
1143 KMNoQuoteReplyToCommand::KMNoQuoteReplyToCommand( TQWidget *parent,
1144  KMMessage *msg )
1145  : KMCommand( parent, msg )
1146 {
1147 }
1148 
1149 KMCommand::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 
1166 KMReplyListCommand::KMReplyListCommand( TQWidget *parent,
1167  KMMessage *msg, const TQString &selection )
1168  : KMCommand( parent, msg ), mSelection( selection )
1169 {
1170 }
1171 
1172 KMCommand::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 
1189 KMReplyToAllCommand::KMReplyToAllCommand( TQWidget *parent,
1190  KMMessage *msg, const TQString &selection )
1191  :KMCommand( parent, msg ), mSelection( selection )
1192 {
1193 }
1194 
1195 KMCommand::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 
1212 KMReplyAuthorCommand::KMReplyAuthorCommand( TQWidget *parent, KMMessage *msg,
1213  const TQString &selection )
1214  : KMCommand( parent, msg ), mSelection( selection )
1215 {
1216 }
1217 
1218 KMCommand::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 
1235 KMForwardInlineCommand::KMForwardInlineCommand( TQWidget *parent,
1236  const TQPtrList<KMMsgBase> &msgList, uint identity )
1237  : KMCommand( parent, msgList ),
1238  mIdentity( identity )
1239 {
1240 }
1241 
1242 KMForwardInlineCommand::KMForwardInlineCommand( TQWidget *parent,
1243  KMMessage *msg, uint identity )
1244  : KMCommand( parent, msg ),
1245  mIdentity( identity )
1246 {
1247 }
1248 
1249 KMCommand::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 
1308 KMForwardAttachedCommand::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 
1315 KMForwardAttachedCommand::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 
1322 KMCommand::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 
1368 KMForwardDigestCommand::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 
1375 KMForwardDigestCommand::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 
1382 KMCommand::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 
1455 KMRedirectCommand::KMRedirectCommand( TQWidget *parent,
1456  KMMessage *msg )
1457  : KMCommand( parent, msg )
1458 {
1459 }
1460 
1461 KMCommand::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 
1485 KMCustomReplyToCommand::KMCustomReplyToCommand( TQWidget *parent, KMMessage *msg,
1486  const TQString &selection,
1487  const TQString &tmpl )
1488  : KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
1489 {
1490 }
1491 
1492 KMCommand::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 
1510 KMCustomReplyAllToCommand::KMCustomReplyAllToCommand( TQWidget *parent, KMMessage *msg,
1511  const TQString &selection,
1512  const TQString &tmpl )
1513  : KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
1514 {
1515 }
1516 
1517 KMCommand::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 
1535 KMCustomForwardCommand::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 
1542 KMCustomForwardCommand::KMCustomForwardCommand( TQWidget *parent,
1543  KMMessage *msg, uint identity, const TQString &tmpl )
1544  : KMCommand( parent, msg ),
1545  mIdentity( identity ), mTemplate( tmpl )
1546 {
1547 }
1548 
1549 KMCommand::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 
1608 KMPrintCommand::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 
1629 void KMPrintCommand::setOverrideFont( const TQFont& font )
1630 {
1631  mOverrideFont = font;
1632 }
1633 
1634 KMCommand::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 
1654 KMSeStatusCommand::KMSeStatusCommand( KMMsgStatus status,
1655  const TQValueList<TQ_UINT32> &serNums, bool toggle )
1656  : mStatus( status ), mSerNums( serNums ), mToggle( toggle )
1657 {
1658 }
1659 
1660 KMCommand::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  //kapp->dcopClient()->emitDCOPSignal( "unreadCountChanged()", TQByteArray() );
1709 
1710  return OK;
1711 }
1712 
1713 
1714 KMFilterCommand::KMFilterCommand( const TQCString &field, const TQString &value )
1715  : mField( field ), mValue( value )
1716 {
1717 }
1718 
1719 KMCommand::Result KMFilterCommand::execute()
1720 {
1721  kmkernel->filterMgr()->createFilter( mField, mValue );
1722 
1723  return OK;
1724 }
1725 
1726 
1727 KMFilterActionCommand::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 
1739 KMCommand::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  TDEApplication::kApplication()->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 
1776 KMMetaFilterActionCommand::KMMetaFilterActionCommand( KMFilter *filter,
1777  KMHeaders *headers,
1778  KMMainWidget *main )
1779  : TQObject( main ),
1780  mFilter( filter ), mHeaders( headers ), mMainWidget( main )
1781 {
1782 }
1783 
1784 void 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 
1813 FolderShortcutCommand::FolderShortcutCommand( KMMainWidget *mainwidget,
1814  KMFolder *folder )
1815  : mMainWidget( mainwidget ), mFolder( folder ), mAction( 0 )
1816 {
1817 }
1818 
1819 
1820 FolderShortcutCommand::~FolderShortcutCommand()
1821 {
1822  if ( mAction ) mAction->unplugAll();
1823  delete mAction;
1824 }
1825 
1826 void FolderShortcutCommand::start()
1827 {
1828  mMainWidget->slotSelectFolder( mFolder );
1829 }
1830 
1831 void FolderShortcutCommand::setAction( TDEAction* action )
1832 {
1833  mAction = action;
1834 }
1835 
1836 KMMailingListFilterCommand::KMMailingListFilterCommand( TQWidget *parent,
1837  KMMessage *msg )
1838  : KMCommand( parent, msg )
1839 {
1840 }
1841 
1842 KMCommand::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 
1859 void 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 
1901 void 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 
1965 KMCopyCommand::KMCopyCommand( KMFolder* destFolder,
1966  const TQPtrList<KMMsgBase> &msgList )
1967 :mDestFolder( destFolder ), mMsgList( msgList )
1968 {
1969  setDeletesItself( true );
1970 }
1971 
1972 KMCopyCommand::KMCopyCommand( KMFolder* destFolder, KMMessage * msg )
1973  :mDestFolder( destFolder )
1974 {
1975  setDeletesItself( true );
1976  mMsgList.append( &msg->toMsgBase() );
1977 }
1978 
1979 KMCommand::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 
2103 void 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 
2126 void 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 
2137 KMMoveCommand::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 
2146 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
2147  KMMessage *msg )
2148  : mDestFolder( destFolder ), mProgressItem( 0 )
2149 {
2150  mSerNumList.append( msg->getMsgSerNum() );
2151 }
2152 
2153 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
2154  KMMsgBase *msgBase )
2155  : mDestFolder( destFolder ), mProgressItem( 0 )
2156 {
2157  mSerNumList.append( msgBase->getMsgSerNum() );
2158 }
2159 
2160 KMMoveCommand::KMMoveCommand( TQ_UINT32 )
2161  : mProgressItem( 0 )
2162 {
2163 }
2164 
2165 KMCommand::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 
2298 void 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 
2320 void 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 
2346 void 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 
2364 void KMMoveCommand::slotMoveCanceled()
2365 {
2366  completeMove( Canceled );
2367 }
2368 
2369 // srcFolder doesn't make much sense for searchFolders
2370 KMDeleteMsgCommand::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 
2378 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg )
2379 :KMMoveCommand( findTrashFolder( srcFolder ), msg)
2380 {
2381  srcFolder->open("kmcommand");
2382  mOpenedFolders.push_back( srcFolder );
2383 }
2384 
2385 KMDeleteMsgCommand::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 
2405 KMFolder * 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 
2416 KMUrlClickedCommand::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 
2423 KMCommand::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 
2488 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, KMMessage *msg )
2489  : KMCommand( parent, msg ), mImplicitAttachments( true ), mEncoded( false )
2490 {
2491 }
2492 
2493 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, const TQPtrList<KMMsgBase>& msgs )
2494  : KMCommand( parent, msgs ), mImplicitAttachments( true ), mEncoded( false )
2495 {
2496 }
2497 
2498 KMSaveAttachmentsCommand::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 
2507 KMCommand::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 
2536 void 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 
2675 KMCommand::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 
2801 KMLoadPartsCommand::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 
2809 KMLoadPartsCommand::KMLoadPartsCommand( partNode *node, KMMessage *msg )
2810  : mNeedsRetrieval( 0 )
2811 {
2812  mPartMap.insert( node, msg );
2813 }
2814 
2815 KMLoadPartsCommand::KMLoadPartsCommand( PartNodeMessageMap& partMap )
2816  : mNeedsRetrieval( 0 ), mPartMap( partMap )
2817 {
2818 }
2819 
2820 void 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 
2846 void 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 
2866 KMCommand::Result KMLoadPartsCommand::execute()
2867 {
2868  emit partsRetrieved();
2869  setResult( OK );
2870  emit completed( this );
2871  deleteLater();
2872  return OK;
2873 }
2874 
2875 KMResendMessageCommand::KMResendMessageCommand( TQWidget *parent,
2876  KMMessage *msg )
2877  :KMCommand( parent, msg )
2878 {
2879 }
2880 
2881 KMCommand::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 
2909 KMMailingListCommand::KMMailingListCommand( TQWidget *parent, KMFolder *folder )
2910  : KMCommand( parent ), mFolder( folder )
2911 {
2912 }
2913 
2914 KMCommand::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 
2941 void KMMailingListCommand::commandCompleted( KMCommand *command )
2942 {
2943  setResult( command->result() );
2944  emit completed( this );
2945  deleteLater();
2946 }
2947 
2948 KMMailingListPostCommand::KMMailingListPostCommand( TQWidget *parent, KMFolder *folder )
2949  : KMMailingListCommand( parent, folder )
2950 {
2951 }
2952 KURL::List KMMailingListPostCommand::urls() const
2953 {
2954  return mFolder->mailingList().postURLS();
2955 }
2956 
2957 KMMailingListSubscribeCommand::KMMailingListSubscribeCommand( TQWidget *parent, KMFolder *folder )
2958  : KMMailingListCommand( parent, folder )
2959 {
2960 }
2961 KURL::List KMMailingListSubscribeCommand::urls() const
2962 {
2963  return mFolder->mailingList().subscribeURLS();
2964 }
2965 
2966 KMMailingListUnsubscribeCommand::KMMailingListUnsubscribeCommand( TQWidget *parent, KMFolder *folder )
2967  : KMMailingListCommand( parent, folder )
2968 {
2969 }
2970 KURL::List KMMailingListUnsubscribeCommand::urls() const
2971 {
2972  return mFolder->mailingList().unsubscribeURLS();
2973 }
2974 
2975 KMMailingListArchivesCommand::KMMailingListArchivesCommand( TQWidget *parent, KMFolder *folder )
2976  : KMMailingListCommand( parent, folder )
2977 {
2978 }
2979 KURL::List KMMailingListArchivesCommand::urls() const
2980 {
2981  return mFolder->mailingList().archiveURLS();
2982 }
2983 
2984 KMMailingListHelpCommand::KMMailingListHelpCommand( TQWidget *parent, KMFolder *folder )
2985  : KMMailingListCommand( parent, folder )
2986 {
2987 }
2988 KURL::List KMMailingListHelpCommand::urls() const
2989 {
2990  return mFolder->mailingList().helpURLS();
2991 }
2992 
2993 KMIMChatCommand::KMIMChatCommand( const KURL &url, KMMessage *msg )
2994  :mUrl( url ), mMessage( msg )
2995 {
2996 }
2997 
2998 KMCommand::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 
3037 KMHandleAttachmentCommand::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 
3045 void 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 
3061 void KMHandleAttachmentCommand::slotPartComplete()
3062 {
3063  execute();
3064 }
3065 
3066 KMCommand::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 
3099 TQString 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 
3129 KService::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 
3156 void 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 
3182 void 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 
3201 void KMHandleAttachmentCommand::atmView()
3202 {
3203  // we do not handle this ourself
3204  emit showAttachment( mAtmId, mAtmName );
3205 }
3206 
3207 void 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 
3217 void KMHandleAttachmentCommand::atmProperties()
3218 {
3219  KMMsgPartDialogCompat dlg( parentWidget() , 0, true );
3220  KMMessagePart& msgPart = mNode->msgPart();
3221  dlg.setMsgPart( &msgPart );
3222  dlg.exec();
3223 }
3224 
3225 void 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 
3313 static 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 
3317 void 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 
3357 void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusUploadResult( TDEIO::Job * job )
3358 {
3359  if ( job->error() )
3360  job->showErrorDialog();
3361  LaterDeleterWithCommandCompletion d( this );
3362  d.setResult( OK );
3363 }
3364 
3365 
3366 AttachmentModifyCommand::AttachmentModifyCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
3367  KMCommand( parent, msg ),
3368  mPartIndex( node->nodeId() ),
3369  mSernum( 0 )
3370 {
3371 }
3372 
3373 AttachmentModifyCommand::AttachmentModifyCommand( int nodeId, KMMessage *msg, TQWidget *parent )
3374  : KMCommand( parent, msg ),
3375  mPartIndex( nodeId ),
3376  mSernum( 0 )
3377 {
3378 }
3379 
3380 AttachmentModifyCommand::~ AttachmentModifyCommand()
3381 {
3382 }
3383 
3384 KMCommand::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 
3404 void 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 
3422 void 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 
3437 void AttachmentModifyCommand::messageDeleteResult(KMCommand * cmd)
3438 {
3439  setResult( cmd->result() );
3440  emit completed( this );
3441  deleteLater();
3442 }
3443 
3444 KMDeleteAttachmentCommand::KMDeleteAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
3445  AttachmentModifyCommand( node, msg, parent )
3446 {
3447  kdDebug(5006) << k_funcinfo << endl;
3448 }
3449 
3450 KMDeleteAttachmentCommand::KMDeleteAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent )
3451  : AttachmentModifyCommand( nodeId, msg, parent )
3452 {
3453  kdDebug(5006) << k_funcinfo << endl;
3454 }
3455 
3456 KMDeleteAttachmentCommand::~KMDeleteAttachmentCommand()
3457 {
3458  kdDebug(5006) << k_funcinfo << endl;
3459 }
3460 
3461 KMCommand::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 
3476 KMEditAttachmentCommand::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 
3483 KMEditAttachmentCommand::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 
3490 KMEditAttachmentCommand::~ KMEditAttachmentCommand()
3491 {
3492 }
3493 
3494 KMCommand::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 
3526 void 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 
3566 CreateTodoCommand::CreateTodoCommand(TQWidget * parent, KMMessage * msg)
3567  : KMCommand( parent, msg )
3568 {
3569 }
3570 
3571 KMCommand::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( kapp->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
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
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
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
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
KMMsgBase & toMsgBase()
Get KMMsgBase for this object.
Definition: kmmessage.h:114
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