kmail

kmcommands.cpp
1 /* -*- mode: C++; c-file-style: "gnu" -*-
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, TQT_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, TQT_SIGNAL( messagesTransfered( KMCommand::Result ) ),
229  this, TQT_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, TQT_SIGNAL( messagesTransfered( KMCommand::Result ) ),
265  this, TQT_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, TQT_SIGNAL(messageRetrieved(KMMessage*)),
343  this, TQT_SLOT(slotMsgTransfered(KMMessage*)));
344  // emitted when the job is destroyed
345  connect(job, TQT_SIGNAL(finished()),
346  this, TQT_SLOT(slotJobFinished()));
347  connect(job, TQT_SIGNAL(progress(unsigned long, unsigned long)),
348  this, TQT_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, TQT_SIGNAL(cancelClicked()),
367  this, TQT_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, TQT_SIGNAL(result(TDEIO::Job*)), TQT_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, TQT_SIGNAL(dataReq(TDEIO::Job*, TQByteArray &)),
849  TQT_SLOT(slotSaveDataReq()));
850  connect(mJob, TQT_SIGNAL(result(TDEIO::Job*)),
851  TQT_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, TQT_SIGNAL( messageRetrieved( KMMessage* ) ),
902  this, TQT_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, TQT_SIGNAL(dataReq(TDEIO::Job*, TQByteArray &)),
975  TQT_SLOT(slotSaveDataReq()));
976  connect(mJob, TQT_SIGNAL(result(TDEIO::Job*)),
977  TQT_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, TQT_SIGNAL( data( TDEIO::Job *, const TQByteArray & ) ),
1018  this, TQT_SLOT( slotDataArrived( TDEIO::Job*, const TQByteArray & ) ) );
1019  connect( mJob, TQT_SIGNAL( result( TDEIO::Job * ) ),
1020  TQT_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->setCharset(msg->charset());
1354  msgPart->setName("forwarded message");
1355  msgPart->setContentDescription(msg->from()+": "+msg->subject());
1356  msgPart->setContentDisposition( "inline" );
1357  // THIS HAS TO BE AFTER setCte()!!!!
1358  msgPart->setMessageBody( KMail::Util::ByteArray( msg->asDwString() ) );
1359  msgPart->setCharset("");
1360 
1361  fwdMsg->link(msg, KMMsgStatusForwarded);
1362  mWin->addAttach(msgPart);
1363  }
1364 
1365  mWin->show();
1366 
1367  return OK;
1368 }
1369 
1370 
1371 KMForwardDigestCommand::KMForwardDigestCommand( TQWidget *parent,
1372  const TQPtrList<KMMsgBase> &msgList, uint identity, KMail::Composer *win )
1373  : KMCommand( parent, msgList ), mIdentity( identity ),
1374  mWin( TQGuardedPtr<KMail::Composer>( win ))
1375 {
1376 }
1377 
1378 KMForwardDigestCommand::KMForwardDigestCommand( TQWidget *parent,
1379  KMMessage * msg, uint identity, KMail::Composer *win )
1380  : KMCommand( parent, msg ), mIdentity( identity ),
1381  mWin( TQGuardedPtr< KMail::Composer >( win ))
1382 {
1383 }
1384 
1385 KMCommand::Result KMForwardDigestCommand::execute()
1386 {
1387  TQPtrList<KMMessage> msgList = retrievedMsgs();
1388 
1389  if ( msgList.count() < 2 )
1390  return Undefined; // must have more than 1 for a digest
1391 
1392  uint id = 0;
1393  KMMessage *fwdMsg = new KMMessage;
1394  KMMessagePart *msgPart = new KMMessagePart;
1395  TQString msgPartText;
1396  int msgCnt = 0; // incase there are some we can't forward for some reason
1397 
1398  // dummy header initialization; initialization with the correct identity
1399  // is done below
1400  fwdMsg->initHeader( id );
1401  fwdMsg->setAutomaticFields( true );
1402  fwdMsg->mMsg->Headers().ContentType().CreateBoundary( 1 );
1403  TQCString boundary( fwdMsg->mMsg->Headers().ContentType().Boundary().c_str() );
1404  msgPartText = i18n("\nThis is a MIME digest forward. The content of the"
1405  " message is contained in the attachment(s).\n\n\n");
1406  // iterate through all the messages to be forwarded
1407  for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
1408  // set the identity
1409  if ( id == 0 )
1410  id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
1411  // set the part header
1412  msgPartText += "--";
1413  msgPartText += TQString::fromLatin1( boundary );
1414  msgPartText += "\nContent-Type: MESSAGE/RFC822";
1415  msgPartText += TQString( "; CHARSET=%1" ).arg( TQString(msg->charset()) );
1416  msgPartText += '\n';
1417  DwHeaders dwh;
1418  dwh.MessageId().CreateDefault();
1419  msgPartText += TQString( "Content-ID: %1\n" ).arg( dwh.MessageId().AsString().c_str() );
1420  msgPartText += TQString( "Content-Description: %1" ).arg( msg->subject() );
1421  if ( !msg->subject().contains( "(fwd)" ) )
1422  msgPartText += " (fwd)";
1423  msgPartText += "\n\n";
1424  // remove headers that shouldn't be forwarded
1426  msg->removeHeaderField( "BCC" );
1427  // set the part
1428  msgPartText += msg->headerAsString();
1429  msgPartText += '\n';
1430  msgPartText += msg->body();
1431  msgPartText += '\n'; // eot
1432  msgCnt++;
1433  fwdMsg->link( msg, KMMsgStatusForwarded );
1434  }
1435 
1436  if ( id == 0 )
1437  id = mIdentity; // use folder identity if no message had an id set
1438  fwdMsg->initHeader( id );
1439  msgPartText += "--";
1440  msgPartText += TQString::fromLatin1( boundary );
1441  msgPartText += "--\n";
1442  TQCString tmp;
1443  msgPart->setTypeStr( "MULTIPART" );
1444  tmp.sprintf( "Digest; boundary=\"%s\"", boundary.data() );
1445  msgPart->setSubtypeStr( tmp );
1446  msgPart->setName( "unnamed" );
1447  msgPart->setCte( DwMime::kCte7bit ); // does it have to be 7bit?
1448  msgPart->setContentDescription( TQString( "Digest of %1 messages." ).arg( msgCnt ) );
1449  // THIS HAS TO BE AFTER setCte()!!!!
1450  msgPart->setBodyEncoded( TQCString( msgPartText.ascii() ) );
1451  KCursorSaver busy( KBusyPtr::busy() );
1452  KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
1453  win->addAttach( msgPart );
1454  win->show();
1455  return OK;
1456 }
1457 
1458 KMRedirectCommand::KMRedirectCommand( TQWidget *parent,
1459  KMMessage *msg )
1460  : KMCommand( parent, msg )
1461 {
1462 }
1463 
1464 KMCommand::Result KMRedirectCommand::execute()
1465 {
1466  KMMessage *msg = retrievedMessage();
1467  if ( !msg || !msg->codec() )
1468  return Failed;
1469 
1470  RedirectDialog dlg( parentWidget(), "redirect", true,
1471  kmkernel->msgSender()->sendImmediate() );
1472  if (dlg.exec()==TQDialog::Rejected) return Failed;
1473 
1474  KMMessage *newMsg = msg->createRedirect( dlg.to() );
1475  KMFilterAction::sendMDN( msg, KMime::MDN::Dispatched );
1476 
1477  const KMail::MessageSender::SendMethod method = dlg.sendImmediate()
1478  ? KMail::MessageSender::SendImmediate
1479  : KMail::MessageSender::SendLater;
1480  if ( !kmkernel->msgSender()->send( newMsg, method ) ) {
1481  kdDebug(5006) << "KMRedirectCommand: could not redirect message (sending failed)" << endl;
1482  return Failed; // error: couldn't send
1483  }
1484  return OK;
1485 }
1486 
1487 
1488 KMCustomReplyToCommand::KMCustomReplyToCommand( TQWidget *parent, KMMessage *msg,
1489  const TQString &selection,
1490  const TQString &tmpl )
1491  : KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
1492 {
1493 }
1494 
1495 KMCommand::Result KMCustomReplyToCommand::execute()
1496 {
1497  KCursorSaver busy(KBusyPtr::busy());
1498  KMMessage *msg = retrievedMessage();
1499  if ( !msg || !msg->codec() ) {
1500  return Failed;
1501  }
1502  KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection,
1503  false, true, mTemplate );
1504  KMail::Composer * win = KMail::makeComposer( reply );
1505  win->setCharset( msg->codec()->mimeName(), true );
1506  win->setReplyFocus();
1507  win->show();
1508 
1509  return OK;
1510 }
1511 
1512 
1513 KMCustomReplyAllToCommand::KMCustomReplyAllToCommand( TQWidget *parent, KMMessage *msg,
1514  const TQString &selection,
1515  const TQString &tmpl )
1516  : KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
1517 {
1518 }
1519 
1520 KMCommand::Result KMCustomReplyAllToCommand::execute()
1521 {
1522  KCursorSaver busy(KBusyPtr::busy());
1523  KMMessage *msg = retrievedMessage();
1524  if ( !msg || !msg->codec() ) {
1525  return Failed;
1526  }
1527  KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection,
1528  false, true, mTemplate );
1529  KMail::Composer * win = KMail::makeComposer( reply );
1530  win->setCharset( msg->codec()->mimeName(), true );
1531  win->setReplyFocus();
1532  win->show();
1533 
1534  return OK;
1535 }
1536 
1537 
1538 KMCustomForwardCommand::KMCustomForwardCommand( TQWidget *parent,
1539  const TQPtrList<KMMsgBase> &msgList, uint identity, const TQString &tmpl )
1540  : KMCommand( parent, msgList ),
1541  mIdentity( identity ), mTemplate( tmpl )
1542 {
1543 }
1544 
1545 KMCustomForwardCommand::KMCustomForwardCommand( TQWidget *parent,
1546  KMMessage *msg, uint identity, const TQString &tmpl )
1547  : KMCommand( parent, msg ),
1548  mIdentity( identity ), mTemplate( tmpl )
1549 {
1550 }
1551 
1552 KMCommand::Result KMCustomForwardCommand::execute()
1553 {
1554  TQPtrList<KMMessage> msgList = retrievedMsgs();
1555 
1556  if (msgList.count() >= 2) { // Multiple forward
1557 
1558  uint id = 0;
1559  TQPtrList<KMMessage> linklist;
1560  for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
1561  // set the identity
1562  if (id == 0)
1563  id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
1564 
1565  // msgText += msg->createForwardBody();
1566  linklist.append( msg );
1567  }
1568  if ( id == 0 )
1569  id = mIdentity; // use folder identity if no message had an id set
1570  KMMessage *fwdMsg = new KMMessage;
1571  fwdMsg->initHeader( id );
1572  fwdMsg->setAutomaticFields( true );
1573  fwdMsg->setCharset( "utf-8" );
1574  // fwdMsg->setBody( msgText );
1575 
1576  for ( KMMessage *msg = linklist.first(); msg; msg = linklist.next() ) {
1577  TemplateParser parser( fwdMsg, TemplateParser::Forward );
1578  parser.setSelection( msg->body() ); // FIXME: Why is this needed?
1579  parser.process( msg, 0, true );
1580 
1581  fwdMsg->link( msg, KMMsgStatusForwarded );
1582  }
1583 
1584  KCursorSaver busy( KBusyPtr::busy() );
1585  KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
1586  win->setCharset("");
1587  win->show();
1588 
1589  } else { // forward a single message at most
1590 
1591  KMMessage *msg = msgList.getFirst();
1592  if ( !msg || !msg->codec() )
1593  return Failed;
1594 
1595  KCursorSaver busy( KBusyPtr::busy() );
1596  KMMessage *fwdMsg = msg->createForward( mTemplate );
1597 
1598  uint id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
1599  if ( id == 0 )
1600  id = mIdentity;
1601  {
1602  KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
1603  win->setCharset( fwdMsg->codec()->mimeName(), true );
1604  win->show();
1605  }
1606  }
1607  return OK;
1608 }
1609 
1610 
1611 KMPrintCommand::KMPrintCommand( TQWidget *parent, KMMessage *msg,
1612  const KMail::HeaderStyle *headerStyle,
1613  const KMail::HeaderStrategy *headerStrategy,
1614  bool htmlOverride, bool htmlLoadExtOverride,
1615  bool useFixedFont, const TQString & encoding )
1616  : KMCommand( parent, msg ),
1617  mHeaderStyle( headerStyle ), mHeaderStrategy( headerStrategy ),
1618  mHtmlOverride( htmlOverride ),
1619  mHtmlLoadExtOverride( htmlLoadExtOverride ),
1620  mUseFixedFont( useFixedFont ), mEncoding( encoding )
1621 {
1622  if ( GlobalSettings::useDefaultFonts() )
1623  mOverrideFont = TDEGlobalSettings::generalFont();
1624  else {
1625  TDEConfigGroup fonts( KMKernel::config(), "Fonts" );
1626  TQString tmp = fonts.readEntry( "print-font", TDEGlobalSettings::generalFont().toString() );
1627  mOverrideFont.fromString( tmp );
1628  }
1629 }
1630 
1631 
1632 void KMPrintCommand::setOverrideFont( const TQFont& font )
1633 {
1634  mOverrideFont = font;
1635 }
1636 
1637 KMCommand::Result KMPrintCommand::execute()
1638 {
1639  KMReaderWin printWin( 0, 0, 0 );
1640  printWin.setPrinting( true );
1641  printWin.readConfig();
1642  if ( mHeaderStyle != 0 && mHeaderStrategy != 0 )
1643  printWin.setHeaderStyleAndStrategy( mHeaderStyle, mHeaderStrategy );
1644  printWin.setHtmlOverride( mHtmlOverride );
1645  printWin.setHtmlLoadExtOverride( mHtmlLoadExtOverride );
1646  printWin.setUseFixedFont( mUseFixedFont );
1647  printWin.setOverrideEncoding( mEncoding );
1648  printWin.cssHelper()->setPrintFont( mOverrideFont );
1649  printWin.setDecryptMessageOverwrite( true );
1650  printWin.setMsg( retrievedMessage(), true );
1651  printWin.printMsg();
1652 
1653  return OK;
1654 }
1655 
1656 
1657 KMSeStatusCommand::KMSeStatusCommand( KMMsgStatus status,
1658  const TQValueList<TQ_UINT32> &serNums, bool toggle )
1659  : mStatus( status ), mSerNums( serNums ), mToggle( toggle )
1660 {
1661 }
1662 
1663 KMCommand::Result KMSeStatusCommand::execute()
1664 {
1665  TQValueListIterator<TQ_UINT32> it;
1666  int idx = -1;
1667  KMFolder *folder = 0;
1668  bool parenStatus = false;
1669 
1670  // Toggle actions on threads toggle the whole thread
1671  // depending on the state of the parent.
1672  if (mToggle) {
1673  KMMsgBase *msg;
1674  KMMsgDict::instance()->getLocation( *mSerNums.begin(), &folder, &idx );
1675  if (folder) {
1676  msg = folder->getMsgBase(idx);
1677  if (msg && (msg->status()&mStatus))
1678  parenStatus = true;
1679  else
1680  parenStatus = false;
1681  }
1682  }
1683  TQMap< KMFolder*, TQValueList<int> > folderMap;
1684  for ( it = mSerNums.begin(); it != mSerNums.end(); ++it ) {
1685  KMMsgDict::instance()->getLocation( *it, &folder, &idx );
1686  if (folder) {
1687  if (mToggle) {
1688  KMMsgBase *msg = folder->getMsgBase(idx);
1689  // check if we are already at the target toggle state
1690  if (msg) {
1691  bool myStatus;
1692  if (msg->status()&mStatus)
1693  myStatus = true;
1694  else
1695  myStatus = false;
1696  if (myStatus != parenStatus)
1697  continue;
1698  }
1699  }
1700  /* Collect the ids for each folder in a separate list and
1701  send them off in one go at the end. */
1702  folderMap[folder].append(idx);
1703  }
1704  }
1705  TQMapIterator< KMFolder*, TQValueList<int> > it2 = folderMap.begin();
1706  while ( it2 != folderMap.end() ) {
1707  KMFolder *f = it2.key();
1708  f->setStatus( (*it2), mStatus, mToggle );
1709  ++it2;
1710  }
1711  //kapp->dcopClient()->emitDCOPSignal( "unreadCountChanged()", TQByteArray() );
1712 
1713  return OK;
1714 }
1715 
1716 
1717 KMFilterCommand::KMFilterCommand( const TQCString &field, const TQString &value )
1718  : mField( field ), mValue( value )
1719 {
1720 }
1721 
1722 KMCommand::Result KMFilterCommand::execute()
1723 {
1724  kmkernel->filterMgr()->createFilter( mField, mValue );
1725 
1726  return OK;
1727 }
1728 
1729 
1730 KMFilterActionCommand::KMFilterActionCommand( TQWidget *parent,
1731  const TQPtrList<KMMsgBase> &msgList,
1732  KMFilter *filter )
1733  : KMCommand( parent, msgList ), mFilter( filter )
1734 {
1735  TQPtrListIterator<KMMsgBase> it(msgList);
1736  while ( it.current() ) {
1737  serNumList.append( (*it)->getMsgSerNum() );
1738  ++it;
1739  }
1740 }
1741 
1742 KMCommand::Result KMFilterActionCommand::execute()
1743 {
1744  KCursorSaver busy( KBusyPtr::busy() );
1745 
1746  int msgCount = 0;
1747  int msgCountToFilter = serNumList.count();
1748  ProgressItem* progressItem =
1749  ProgressManager::createProgressItem ( "filter"+ProgressManager::getUniqueID(),
1750  i18n( "Filtering messages" ) );
1751  progressItem->setTotalItems( msgCountToFilter );
1752  TQValueList<TQ_UINT32>::const_iterator it;
1753  for ( it = serNumList.begin(); it != serNumList.end(); it++ ) {
1754  TQ_UINT32 serNum = *it;
1755  int diff = msgCountToFilter - ++msgCount;
1756  if ( diff < 10 || !( msgCount % 20 ) || msgCount <= 10 ) {
1757  progressItem->updateProgress();
1758  TQString statusMsg = i18n("Filtering message %1 of %2");
1759  statusMsg = statusMsg.arg( msgCount ).arg( msgCountToFilter );
1760  KPIM::BroadcastStatus::instance()->setStatusMsg( statusMsg );
1761  TDEApplication::kApplication()->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput, 50 );
1762  }
1763 
1764  int filterResult = kmkernel->filterMgr()->process( serNum, mFilter );
1765  if (filterResult == 2) {
1766  // something went horribly wrong (out of space?)
1767  perror("Critical error");
1768  kmkernel->emergencyExit( i18n("Not enough free disk space?" ));
1769  }
1770  progressItem->incCompletedItems();
1771  }
1772 
1773  progressItem->setComplete();
1774  progressItem = 0;
1775  return OK;
1776 }
1777 
1778 
1779 KMMetaFilterActionCommand::KMMetaFilterActionCommand( KMFilter *filter,
1780  KMHeaders *headers,
1781  KMMainWidget *main )
1782  : TQObject( main ),
1783  mFilter( filter ), mHeaders( headers ), mMainWidget( main )
1784 {
1785 }
1786 
1787 void KMMetaFilterActionCommand::start()
1788 {
1789  if (ActionScheduler::isEnabled() ) {
1790  // use action scheduler
1791  KMFilterMgr::FilterSet set = KMFilterMgr::All;
1792  TQValueList<KMFilter*> filters;
1793  filters.append( mFilter );
1794  ActionScheduler *scheduler = new ActionScheduler( set, filters, mHeaders );
1795  scheduler->setAlwaysMatch( true );
1796  scheduler->setAutoDestruct( true );
1797 
1798  int contentX, contentY;
1799  HeaderItem *nextItem = mHeaders->prepareMove( &contentX, &contentY );
1800  TQPtrList<KMMsgBase> msgList = *mHeaders->selectedMsgs(true);
1801  mHeaders->finalizeMove( nextItem, contentX, contentY );
1802 
1803  for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
1804  scheduler->execFilters( msg );
1805  } else {
1806  KMCommand *filterCommand =
1807  new KMFilterActionCommand( mMainWidget,
1808  *mHeaders->selectedMsgs(), mFilter );
1809  filterCommand->start();
1810  int contentX, contentY;
1811  HeaderItem *item = mHeaders->prepareMove( &contentX, &contentY );
1812  mHeaders->finalizeMove( item, contentX, contentY );
1813  }
1814 }
1815 
1816 FolderShortcutCommand::FolderShortcutCommand( KMMainWidget *mainwidget,
1817  KMFolder *folder )
1818  : mMainWidget( mainwidget ), mFolder( folder ), mAction( 0 )
1819 {
1820 }
1821 
1822 
1823 FolderShortcutCommand::~FolderShortcutCommand()
1824 {
1825  if ( mAction ) mAction->unplugAll();
1826  delete mAction;
1827 }
1828 
1829 void FolderShortcutCommand::start()
1830 {
1831  mMainWidget->slotSelectFolder( mFolder );
1832 }
1833 
1834 void FolderShortcutCommand::setAction( TDEAction* action )
1835 {
1836  mAction = action;
1837 }
1838 
1839 KMMailingListFilterCommand::KMMailingListFilterCommand( TQWidget *parent,
1840  KMMessage *msg )
1841  : KMCommand( parent, msg )
1842 {
1843 }
1844 
1845 KMCommand::Result KMMailingListFilterCommand::execute()
1846 {
1847  TQCString name;
1848  TQString value;
1849  KMMessage *msg = retrievedMessage();
1850  if (!msg)
1851  return Failed;
1852 
1853  if ( !MailingList::name( msg, name, value ).isEmpty() ) {
1854  kmkernel->filterMgr()->createFilter( name, value );
1855  return OK;
1856  }
1857  else
1858  return Failed;
1859 }
1860 
1861 
1862 void KMMenuCommand::folderToPopupMenu(bool move,
1863  TQObject *receiver, KMMenuToFolder *aMenuToFolder, TQPopupMenu *menu )
1864 {
1865  while ( menu->count() )
1866  {
1867  TQPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
1868  if (popup)
1869  delete popup;
1870  else
1871  menu->removeItemAt( 0 );
1872  }
1873 
1874  if (!kmkernel->imapFolderMgr()->dir().first() &&
1875  !kmkernel->dimapFolderMgr()->dir().first())
1876  { // only local folders
1877  makeFolderMenu( &kmkernel->folderMgr()->dir(), move,
1878  receiver, aMenuToFolder, menu );
1879  } else {
1880  // operate on top-level items
1881  TQPopupMenu* subMenu = new TQPopupMenu(menu);
1882  makeFolderMenu( &kmkernel->folderMgr()->dir(),
1883  move, receiver, aMenuToFolder, subMenu );
1884  menu->insertItem( i18n( "Local Folders" ), subMenu );
1885  KMFolderDir* fdir = &kmkernel->imapFolderMgr()->dir();
1886  for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
1887  if (node->isDir())
1888  continue;
1889  subMenu = new TQPopupMenu(menu);
1890  makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
1891  menu->insertItem( node->label(), subMenu );
1892  }
1893  fdir = &kmkernel->dimapFolderMgr()->dir();
1894  for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
1895  if (node->isDir())
1896  continue;
1897  subMenu = new TQPopupMenu(menu);
1898  makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
1899  menu->insertItem( node->label(), subMenu );
1900  }
1901  }
1902 }
1903 
1904 void KMMenuCommand::makeFolderMenu(KMFolderNode* node, bool move,
1905  TQObject *receiver, KMMenuToFolder *aMenuToFolder, TQPopupMenu *menu )
1906 {
1907  // connect the signals
1908  if (move)
1909  {
1910  disconnect(menu, TQT_SIGNAL(activated(int)), receiver,
1911  TQT_SLOT(moveSelectedToFolder(int)));
1912  connect(menu, TQT_SIGNAL(activated(int)), receiver,
1913  TQT_SLOT(moveSelectedToFolder(int)));
1914  } else {
1915  disconnect(menu, TQT_SIGNAL(activated(int)), receiver,
1916  TQT_SLOT(copySelectedToFolder(int)));
1917  connect(menu, TQT_SIGNAL(activated(int)), receiver,
1918  TQT_SLOT(copySelectedToFolder(int)));
1919  }
1920 
1921  KMFolder *folder = 0;
1922  KMFolderDir *folderDir = 0;
1923  if (node->isDir()) {
1924  folderDir = static_cast<KMFolderDir*>(node);
1925  } else {
1926  folder = static_cast<KMFolder*>(node);
1927  folderDir = folder->child();
1928  }
1929 
1930  if (folder && !folder->noContent())
1931  {
1932  int menuId;
1933  if (move)
1934  menuId = menu->insertItem(i18n("Move to This Folder"));
1935  else
1936  menuId = menu->insertItem(i18n("Copy to This Folder"));
1937  aMenuToFolder->insert( menuId, folder );
1938  menu->setItemEnabled( menuId, !folder->isReadOnly() );
1939  menu->insertSeparator();
1940  }
1941 
1942  if (!folderDir)
1943  return;
1944 
1945  for (KMFolderNode *it = folderDir->first(); it; it = folderDir->next() ) {
1946  if (it->isDir())
1947  continue;
1948  KMFolder *child = static_cast<KMFolder*>(it);
1949  TQString label = child->label();
1950  label.replace("&","&&");
1951  if (child->child() && child->child()->first()) {
1952  // descend
1953  TQPopupMenu *subMenu = new TQPopupMenu(menu, "subMenu");
1954  makeFolderMenu( child, move, receiver,
1955  aMenuToFolder, subMenu );
1956  menu->insertItem( label, subMenu );
1957  } else {
1958  // insert an item
1959  int menuId = menu->insertItem( label );
1960  aMenuToFolder->insert( menuId, child );
1961  menu->setItemEnabled( menuId, !child->isReadOnly() );
1962  }
1963  }
1964  return;
1965 }
1966 
1967 
1968 KMCopyCommand::KMCopyCommand( KMFolder* destFolder,
1969  const TQPtrList<KMMsgBase> &msgList )
1970 :mDestFolder( destFolder ), mMsgList( msgList )
1971 {
1972  setDeletesItself( true );
1973 }
1974 
1975 KMCopyCommand::KMCopyCommand( KMFolder* destFolder, KMMessage * msg )
1976  :mDestFolder( destFolder )
1977 {
1978  setDeletesItself( true );
1979  mMsgList.append( &msg->toMsgBase() );
1980 }
1981 
1982 KMCommand::Result KMCopyCommand::execute()
1983 {
1984  KMMsgBase *msgBase;
1985  KMMessage *msg, *newMsg;
1986  int idx = -1;
1987  bool isMessage;
1988  TQPtrList<KMMessage> list;
1989  TQPtrList<KMMessage> localList;
1990 
1991  if (mDestFolder && mDestFolder->open("kmcommand") != 0)
1992  {
1993  deleteLater();
1994  return Failed;
1995  }
1996 
1997  setEmitsCompletedItself( true );
1998  KCursorSaver busy(KBusyPtr::busy());
1999 
2000  for (msgBase = mMsgList.first(); msgBase; msgBase = mMsgList.next() )
2001  {
2002  KMFolder *srcFolder = msgBase->parent();
2003  if (( isMessage = msgBase->isMessage() ))
2004  {
2005  msg = static_cast<KMMessage*>(msgBase);
2006  } else {
2007  idx = srcFolder->find(msgBase);
2008  assert(idx != -1);
2009  msg = srcFolder->getMsg(idx);
2010  // corrupt IMAP cache, see FolderStorage::getMsg()
2011  if ( msg == 0 ) {
2012  KMessageBox::error( parentWidget(), i18n("Corrupt IMAP cache detected in folder %1. "
2013  "Copying of messages aborted.").arg( srcFolder->prettyURL() ) );
2014  deleteLater();
2015  return Failed;
2016  }
2017  }
2018 
2019  if (srcFolder && mDestFolder &&
2020  (srcFolder->folderType()== KMFolderTypeImap) &&
2021  (mDestFolder->folderType() == KMFolderTypeImap) &&
2022  (static_cast<KMFolderImap*>(srcFolder->storage())->account() ==
2023  static_cast<KMFolderImap*>(mDestFolder->storage())->account()))
2024  {
2025  // imap => imap with same account
2026  list.append(msg);
2027  } else {
2028  newMsg = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
2029  newMsg->setComplete(msg->isComplete());
2030  // make sure the attachment state is only calculated when it's complete
2031  if (!newMsg->isComplete())
2032  newMsg->setReadyToShow(false);
2033  newMsg->setStatus(msg->status());
2034 
2035  if (srcFolder && !newMsg->isComplete())
2036  {
2037  // imap => others
2038  newMsg->setParent(msg->parent());
2039  FolderJob *job = srcFolder->createJob(newMsg);
2040  job->setCancellable( false );
2041  mPendingJobs << job;
2042  connect(job, TQT_SIGNAL(messageRetrieved(KMMessage*)),
2043  mDestFolder, TQT_SLOT(reallyAddCopyOfMsg(KMMessage*)));
2044  connect( job, TQT_SIGNAL(result(KMail::FolderJob*)),
2045  this, TQT_SLOT(slotJobFinished(KMail::FolderJob*)) );
2046  job->start();
2047  } else {
2048  // local => others
2049  localList.append(newMsg);
2050  }
2051  }
2052 
2053  if (srcFolder && !isMessage && list.isEmpty())
2054  {
2055  assert(idx != -1);
2056  srcFolder->unGetMsg( idx );
2057  }
2058 
2059  } // end for
2060 
2061  bool deleteNow = false;
2062  if (!localList.isEmpty())
2063  {
2064  TQValueList<int> index;
2065  mDestFolder->addMsg( localList, index );
2066  for ( TQValueListIterator<int> it = index.begin(); it != index.end(); ++it ) {
2067  mDestFolder->unGetMsg( *it );
2068  }
2069  if ( mDestFolder->folderType() == KMFolderTypeImap ) {
2070  if ( mPendingJobs.isEmpty() ) {
2071  // wait for the end of the copy before closing the folder
2072  KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
2073  connect( imapDestFolder, TQT_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
2074  this, TQT_SLOT( slotFolderComplete( KMFolderImap*, bool ) ) );
2075  }
2076  } else {
2077  deleteNow = list.isEmpty() && mPendingJobs.isEmpty(); // we're done if there are no other mails we need to fetch
2078  }
2079  }
2080 
2081 //TODO: Get rid of the other cases just use this one for all types of folder
2082 //TODO: requires adding copyMsg and getFolder methods to KMFolder.h
2083  if (!list.isEmpty())
2084  {
2085  // copy the message(s); note: the list is empty afterwards!
2086  KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
2087  connect( imapDestFolder, TQT_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
2088  this, TQT_SLOT( slotFolderComplete( KMFolderImap*, bool ) ) );
2089  imapDestFolder->copyMsg(list);
2090  imapDestFolder->getFolder();
2091  }
2092 
2093  // only close the folder and delete the job if we're done
2094  // otherwise this is done in slotMsgAdded or slotFolderComplete
2095  if ( deleteNow )
2096  {
2097  mDestFolder->close("kmcommand");
2098  setResult( OK );
2099  emit completed( this );
2100  deleteLater();
2101  }
2102 
2103  return OK;
2104 }
2105 
2106 void KMCopyCommand::slotJobFinished(KMail::FolderJob * job)
2107 {
2108  mPendingJobs.remove( job );
2109  if ( job->error() ) {
2110  kdDebug(5006) << k_funcinfo << "folder job failed: " << job->error() << endl;
2111  // kill all pending jobs
2112  for ( TQValueList<KMail::FolderJob*>::Iterator it = mPendingJobs.begin(); it != mPendingJobs.end(); ++it ) {
2113  disconnect( (*it), TQT_SIGNAL(result(KMail::FolderJob*)),
2114  this, TQT_SLOT(slotJobFinished(KMail::FolderJob*)) );
2115  (*it)->kill();
2116  }
2117  mPendingJobs.clear();
2118  setResult( Failed );
2119  }
2120 
2121  if ( mPendingJobs.isEmpty() )
2122  {
2123  mDestFolder->close("kmcommand");
2124  emit completed( this );
2125  deleteLater();
2126  }
2127 }
2128 
2129 void KMCopyCommand::slotFolderComplete( KMFolderImap*, bool success )
2130 {
2131  kdDebug(5006) << k_funcinfo << success << endl;
2132  if ( !success )
2133  setResult( Failed );
2134  mDestFolder->close( "kmcommand" );
2135  emit completed( this );
2136  deleteLater();
2137 }
2138 
2139 
2140 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
2141  const TQPtrList<KMMsgBase> &msgList)
2142  : mDestFolder( destFolder ), mProgressItem( 0 )
2143 {
2144  TQPtrList<KMMsgBase> tmp = msgList;
2145  for ( KMMsgBase *msgBase = tmp.first(); msgBase; msgBase = tmp.next() )
2146  mSerNumList.append( msgBase->getMsgSerNum() );
2147 }
2148 
2149 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
2150  KMMessage *msg )
2151  : mDestFolder( destFolder ), mProgressItem( 0 )
2152 {
2153  mSerNumList.append( msg->getMsgSerNum() );
2154 }
2155 
2156 KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
2157  KMMsgBase *msgBase )
2158  : mDestFolder( destFolder ), mProgressItem( 0 )
2159 {
2160  mSerNumList.append( msgBase->getMsgSerNum() );
2161 }
2162 
2163 KMMoveCommand::KMMoveCommand( TQ_UINT32 )
2164  : mProgressItem( 0 )
2165 {
2166 }
2167 
2168 KMCommand::Result KMMoveCommand::execute()
2169 {
2170  setEmitsCompletedItself( true );
2171  setDeletesItself( true );
2172  typedef TQMap< KMFolder*, TQPtrList<KMMessage>* > FolderToMessageListMap;
2173  FolderToMessageListMap folderDeleteList;
2174 
2175  if (mDestFolder && mDestFolder->open("kmcommand") != 0) {
2176  completeMove( Failed );
2177  return Failed;
2178  }
2179  KCursorSaver busy(KBusyPtr::busy());
2180 
2181  // TODO set SSL state according to source and destfolder connection?
2182  Q_ASSERT( !mProgressItem );
2183  mProgressItem =
2184  ProgressManager::createProgressItem (
2185  "move"+ProgressManager::getUniqueID(),
2186  mDestFolder ? i18n( "Moving messages" ) : i18n( "Deleting messages" ) );
2187  connect( mProgressItem, TQT_SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
2188  this, TQT_SLOT( slotMoveCanceled() ) );
2189 
2190  KMMessage *msg;
2191  int rc = 0;
2192  int index;
2193  TQPtrList<KMMessage> list;
2194  int undoId = -1;
2195  mCompleteWithAddedMsg = false;
2196 
2197  if (mDestFolder) {
2198  connect (mDestFolder, TQT_SIGNAL(msgAdded(KMFolder*, TQ_UINT32)),
2199  this, TQT_SLOT(slotMsgAddedToDestFolder(KMFolder*, TQ_UINT32)));
2200  mLostBoys = mSerNumList;
2201  }
2202  mProgressItem->setTotalItems( mSerNumList.count() );
2203 
2204  for ( TQValueList<TQ_UINT32>::ConstIterator it = mSerNumList.constBegin(); it != mSerNumList.constEnd(); ++it ) {
2205  if ( *it == 0 ) {
2206  kdDebug(5006) << k_funcinfo << "serial number == 0!" << endl;
2207  continue; // invalid message
2208  }
2209  KMFolder *srcFolder = 0;
2210  int idx = -1;
2211  KMMsgDict::instance()->getLocation( *it, &srcFolder, &idx );
2212  if (srcFolder == mDestFolder)
2213  continue;
2214  assert(srcFolder);
2215  assert(idx != -1);
2216  if ( !srcFolder->isOpened() ) {
2217  srcFolder->open( "kmmovecommand" );
2218  mOpenedFolders.append( srcFolder );
2219  }
2220  msg = srcFolder->getMsg(idx);
2221  if ( !msg ) {
2222  kdDebug(5006) << k_funcinfo << "No message found for serial number " << *it << endl;
2223  continue;
2224  }
2225  bool undo = msg->enableUndo();
2226 
2227  if ( msg && msg->transferInProgress() &&
2228  srcFolder->folderType() == KMFolderTypeImap )
2229  {
2230  // cancel the download
2231  msg->setTransferInProgress( false, true );
2232  static_cast<KMFolderImap*>(srcFolder->storage())->ignoreJobsForMessage( msg );
2233  }
2234 
2235  if (mDestFolder) {
2236  if (mDestFolder->folderType() == KMFolderTypeImap) {
2237  /* If we are moving to an imap folder, connect to it's completed
2238  * signal so we notice when all the mails should have showed up in it
2239  * but haven't for some reason. */
2240  KMFolderImap *imapFolder = static_cast<KMFolderImap*> ( mDestFolder->storage() );
2241  disconnect (imapFolder, TQT_SIGNAL(folderComplete( KMFolderImap*, bool )),
2242  this, TQT_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
2243 
2244  connect (imapFolder, TQT_SIGNAL(folderComplete( KMFolderImap*, bool )),
2245  this, TQT_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
2246  list.append(msg);
2247  } else {
2248  // We are moving to a local folder.
2249  if ( srcFolder->folderType() == KMFolderTypeImap )
2250  {
2251  // do not complete here but wait until all messages are transferred
2252  mCompleteWithAddedMsg = true;
2253  }
2254  rc = mDestFolder->moveMsg(msg, &index);
2255  if (rc == 0 && index != -1) {
2256  KMMsgBase *mb = mDestFolder->unGetMsg( mDestFolder->count() - 1 );
2257  if (undo && mb)
2258  {
2259  if ( undoId == -1 )
2260  undoId = kmkernel->undoStack()->newUndoAction( srcFolder, mDestFolder );
2261  kmkernel->undoStack()->addMsgToAction( undoId, mb->getMsgSerNum() );
2262  }
2263  } else if (rc != 0) {
2264  // Something went wrong. Stop processing here, it is likely that the
2265  // other moves would fail as well.
2266  completeMove( Failed );
2267  return Failed;
2268  }
2269  }
2270  } else {
2271  // really delete messages that are already in the trash folder or if
2272  // we are really, really deleting, not just moving to trash
2273  if (srcFolder->folderType() == KMFolderTypeImap) {
2274  if (!folderDeleteList[srcFolder])
2275  folderDeleteList[srcFolder] = new TQPtrList<KMMessage>;
2276  folderDeleteList[srcFolder]->append( msg );
2277  } else {
2278  srcFolder->removeMsg(idx);
2279  delete msg;
2280  }
2281  }
2282  }
2283  if (!list.isEmpty() && mDestFolder) {
2284  // will be completed with folderComplete signal
2285  mDestFolder->moveMsg(list, &index);
2286  } else {
2287  FolderToMessageListMap::Iterator it;
2288  for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) {
2289  it.key()->removeMsg(*it.data());
2290  delete it.data();
2291  }
2292  if ( !mCompleteWithAddedMsg ) {
2293  // imap folders will be completed in slotMsgAddedToDestFolder
2294  completeMove( OK );
2295  }
2296  }
2297 
2298  return OK;
2299 }
2300 
2301 void KMMoveCommand::slotImapFolderCompleted(KMFolderImap* imapFolder, bool success)
2302 {
2303  disconnect (imapFolder, TQT_SIGNAL(folderComplete( KMFolderImap*, bool )),
2304  this, TQT_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
2305  if ( success ) {
2306  // the folder was checked successfully but we were still called, so check
2307  // if we are still waiting for messages to show up. If so, uidValidity
2308  // changed, or something else went wrong. Clean up.
2309 
2310  /* Unfortunately older UW imap servers change uid validity for each put job.
2311  * Yes, it is really that broken. *sigh* So we cannot report error here, I guess. */
2312  if ( !mLostBoys.isEmpty() ) {
2313  kdDebug(5006) << "### Not all moved messages reported back that they were " << endl
2314  << "### added to the target folder. Did uidValidity change? " << endl;
2315  }
2316  completeMove( OK );
2317  } else {
2318  // Should we inform the user here or leave that to the caller?
2319  completeMove( Failed );
2320  }
2321 }
2322 
2323 void KMMoveCommand::slotMsgAddedToDestFolder(KMFolder *folder, TQ_UINT32 serNum)
2324 {
2325  if ( folder != mDestFolder || mLostBoys.find( serNum ) == mLostBoys.end() ) {
2326  //kdDebug(5006) << "KMMoveCommand::msgAddedToDestFolder different "
2327  // "folder or invalid serial number." << endl;
2328  return;
2329  }
2330  mLostBoys.remove(serNum);
2331  if ( mLostBoys.isEmpty() ) {
2332  // we are done. All messages transferred to the host succesfully
2333  disconnect (mDestFolder, TQT_SIGNAL(msgAdded(KMFolder*, TQ_UINT32)),
2334  this, TQT_SLOT(slotMsgAddedToDestFolder(KMFolder*, TQ_UINT32)));
2335  if (mDestFolder && mDestFolder->folderType() != KMFolderTypeImap) {
2336  mDestFolder->sync();
2337  }
2338  if ( mCompleteWithAddedMsg ) {
2339  completeMove( OK );
2340  }
2341  } else {
2342  if ( mProgressItem ) {
2343  mProgressItem->incCompletedItems();
2344  mProgressItem->updateProgress();
2345  }
2346  }
2347 }
2348 
2349 void KMMoveCommand::completeMove( Result result )
2350 {
2351  if ( mDestFolder )
2352  mDestFolder->close("kmcommand");
2353  while ( !mOpenedFolders.empty() ) {
2354  KMFolder *folder = mOpenedFolders.back();
2355  mOpenedFolders.pop_back();
2356  folder->close("kmcommand");
2357  }
2358  if ( mProgressItem ) {
2359  mProgressItem->setComplete();
2360  mProgressItem = 0;
2361  }
2362  setResult( result );
2363  emit completed( this );
2364  deleteLater();
2365 }
2366 
2367 void KMMoveCommand::slotMoveCanceled()
2368 {
2369  completeMove( Canceled );
2370 }
2371 
2372 // srcFolder doesn't make much sense for searchFolders
2373 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder,
2374  const TQPtrList<KMMsgBase> &msgList )
2375 :KMMoveCommand( findTrashFolder( srcFolder ), msgList)
2376 {
2377  srcFolder->open("kmcommand");
2378  mOpenedFolders.push_back( srcFolder );
2379 }
2380 
2381 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg )
2382 :KMMoveCommand( findTrashFolder( srcFolder ), msg)
2383 {
2384  srcFolder->open("kmcommand");
2385  mOpenedFolders.push_back( srcFolder );
2386 }
2387 
2388 KMDeleteMsgCommand::KMDeleteMsgCommand( TQ_UINT32 sernum )
2389 :KMMoveCommand( sernum )
2390 {
2391  if ( !sernum ) {
2392  setDestFolder( 0 );
2393  return;
2394  }
2395 
2396  KMFolder *srcFolder = 0;
2397  int idx;
2398  KMMsgDict::instance()->getLocation( sernum, &srcFolder, &idx );
2399  if ( srcFolder ) {
2400  KMMsgBase *msg = srcFolder->getMsgBase( idx );
2401  srcFolder->open("kmcommand");
2402  mOpenedFolders.push_back( srcFolder );
2403  addMsg( msg );
2404  }
2405  setDestFolder( findTrashFolder( srcFolder ) );
2406 }
2407 
2408 KMFolder * KMDeleteMsgCommand::findTrashFolder( KMFolder * folder )
2409 {
2410  KMFolder* trash = folder->trashFolder();
2411  if( !trash )
2412  trash = kmkernel->trashFolder();
2413  if( trash != folder )
2414  return trash;
2415  return 0;
2416 }
2417 
2418 
2419 KMUrlClickedCommand::KMUrlClickedCommand( const KURL &url, uint identity,
2420  KMReaderWin *readerWin, bool htmlPref, KMMainWidget *mainWidget )
2421  :mUrl( url ), mIdentity( identity ), mReaderWin( readerWin ),
2422  mHtmlPref( htmlPref ), mMainWidget( mainWidget )
2423 {
2424 }
2425 
2426 KMCommand::Result KMUrlClickedCommand::execute()
2427 {
2428  KMMessage* msg;
2429 
2430  if (mUrl.protocol() == "mailto")
2431  {
2432  msg = new KMMessage;
2433  msg->initHeader(mIdentity);
2434  msg->setCharset("utf-8");
2435  msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
2436  TQString query=mUrl.query();
2437  while (!query.isEmpty()) {
2438  TQString queryPart;
2439  int secondQuery = query.find('?',1);
2440  if (secondQuery != -1)
2441  queryPart = query.left(secondQuery);
2442  else
2443  queryPart = query;
2444  query = query.mid(queryPart.length());
2445 
2446  if (queryPart.left(9) == "?subject=")
2447  msg->setSubject( KURL::decode_string(queryPart.mid(9)) );
2448  else if (queryPart.left(6) == "?body=")
2449  // It is correct to convert to latin1() as URL should not contain
2450  // anything except ascii.
2451  msg->setBody( KURL::decode_string(queryPart.mid(6)).latin1() );
2452  else if (queryPart.left(4) == "?cc=")
2453  msg->setCc( KURL::decode_string(queryPart.mid(4)) );
2454  }
2455 
2456  KMail::Composer * win = KMail::makeComposer( msg, mIdentity );
2457  win->setCharset("", true);
2458  win->show();
2459  }
2460  else if ( mUrl.protocol() == "im" )
2461  {
2462  kmkernel->imProxy()->chatWithContact( mUrl.path() );
2463  }
2464  else if ((mUrl.protocol() == "http") || (mUrl.protocol() == "https") ||
2465  (mUrl.protocol() == "ftp") || (mUrl.protocol() == "file") ||
2466  (mUrl.protocol() == "ftps") || (mUrl.protocol() == "sftp" ) ||
2467  (mUrl.protocol() == "help") || (mUrl.protocol() == "vnc") ||
2468  (mUrl.protocol() == "smb") || (mUrl.protocol() == "fish") ||
2469  (mUrl.protocol() == "news"))
2470  {
2471  KPIM::BroadcastStatus::instance()->setStatusMsg( i18n("Opening URL..."));
2472  KMimeType::Ptr mime = KMimeType::findByURL( mUrl );
2473  if (mime->name() == "application/x-desktop" ||
2474  mime->name() == "application/x-executable" ||
2475  mime->name() == "application/x-msdos-program" ||
2476  mime->name() == "application/x-shellscript" )
2477  {
2478  if (KMessageBox::warningYesNo( 0, i18n( "<qt>Do you really want to execute <b>%1</b>?</qt>" )
2479  .arg( mUrl.prettyURL() ), TQString(), i18n("Execute"), KStdGuiItem::cancel() ) != KMessageBox::Yes)
2480  return Canceled;
2481  }
2482  KRun * runner = new KRun( mUrl );
2483  runner->setRunExecutables( false );
2484  }
2485  else
2486  return Failed;
2487 
2488  return OK;
2489 }
2490 
2491 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, KMMessage *msg )
2492  : KMCommand( parent, msg ), mImplicitAttachments( true ), mEncoded( false )
2493 {
2494 }
2495 
2496 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, const TQPtrList<KMMsgBase>& msgs )
2497  : KMCommand( parent, msgs ), mImplicitAttachments( true ), mEncoded( false )
2498 {
2499 }
2500 
2501 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, TQPtrList<partNode>& attachments,
2502  KMMessage *msg, bool encoded )
2503  : KMCommand( parent ), mImplicitAttachments( false ), mEncoded( encoded )
2504 {
2505  for ( TQPtrListIterator<partNode> it( attachments ); it.current(); ++it ) {
2506  mAttachmentMap.insert( it.current(), msg );
2507  }
2508 }
2509 
2510 KMCommand::Result KMSaveAttachmentsCommand::execute()
2511 {
2512  setEmitsCompletedItself( true );
2513  if ( mImplicitAttachments ) {
2514  TQPtrList<KMMessage> msgList = retrievedMsgs();
2515  KMMessage *msg;
2516  for ( TQPtrListIterator<KMMessage> itr( msgList );
2517  ( msg = itr.current() );
2518  ++itr ) {
2519  partNode *rootNode = partNode::fromMessage( msg );
2520  for ( partNode *child = rootNode; child;
2521  child = child->firstChild() ) {
2522  for ( partNode *node = child; node; node = node->nextSibling() ) {
2523  if ( node->type() != DwMime::kTypeMultipart )
2524  mAttachmentMap.insert( node, msg );
2525  }
2526  }
2527  }
2528  }
2529  setDeletesItself( true );
2530  // load all parts
2531  KMLoadPartsCommand *command = new KMLoadPartsCommand( mAttachmentMap );
2532  connect( command, TQT_SIGNAL( partsRetrieved() ),
2533  this, TQT_SLOT( slotSaveAll() ) );
2534  command->start();
2535 
2536  return OK;
2537 }
2538 
2539 void KMSaveAttachmentsCommand::slotSaveAll()
2540 {
2541  // now that all message parts have been retrieved, remove all parts which
2542  // don't represent an attachment if they were not explicitely passed in the
2543  // c'tor
2544  if ( mImplicitAttachments ) {
2545  for ( PartNodeMessageMap::iterator it = mAttachmentMap.begin();
2546  it != mAttachmentMap.end(); ) {
2547  // only body parts which have a filename or a name parameter (except for
2548  // the root node for which name is set to the message's subject) are
2549  // considered attachments
2550  if ( it.key()->msgPart().fileName().stripWhiteSpace().isEmpty() &&
2551  ( it.key()->msgPart().name().stripWhiteSpace().isEmpty() ||
2552  !it.key()->parentNode() ) ) {
2553  PartNodeMessageMap::iterator delIt = it;
2554  ++it;
2555  mAttachmentMap.remove( delIt );
2556  }
2557  else
2558  ++it;
2559  }
2560  if ( mAttachmentMap.isEmpty() ) {
2561  KMessageBox::information( 0, i18n("Found no attachments to save.") );
2562  setResult( OK ); // The user has already been informed.
2563  emit completed( this );
2564  deleteLater();
2565  return;
2566  }
2567  }
2568 
2569  KURL url, dirUrl;
2570  if ( mAttachmentMap.count() > 1 ) {
2571  // get the dir
2572  dirUrl = KDirSelectDialog::selectDirectory( TQString(), false,
2573  parentWidget(),
2574  i18n("Save Attachments To") );
2575  if ( !dirUrl.isValid() ) {
2576  setResult( Canceled );
2577  emit completed( this );
2578  deleteLater();
2579  return;
2580  }
2581 
2582  // we may not get a slash-terminated url out of KDirSelectDialog
2583  dirUrl.adjustPath( 1 );
2584  }
2585  else {
2586  // only one item, get the desired filename
2587  partNode *node = mAttachmentMap.begin().key();
2588  // replace all ':' with '_' because ':' isn't allowed on FAT volumes
2589  TQString s =
2590  node->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
2591  if ( s.isEmpty() )
2592  s = node->msgPart().name().stripWhiteSpace().replace( ':', '_' );
2593  if ( s.isEmpty() )
2594  s = i18n("filename for an unnamed attachment", "attachment.1");
2595  url = KFileDialog::getSaveURL( s, TQString(), parentWidget(),
2596  TQString() );
2597  if ( url.isEmpty() ) {
2598  setResult( Canceled );
2599  emit completed( this );
2600  deleteLater();
2601  return;
2602  }
2603  }
2604 
2605  TQMap< TQString, int > renameNumbering;
2606 
2607  Result globalResult = OK;
2608  int unnamedAtmCount = 0;
2609  for ( PartNodeMessageMap::const_iterator it = mAttachmentMap.begin();
2610  it != mAttachmentMap.end();
2611  ++it ) {
2612  KURL curUrl;
2613  if ( !dirUrl.isEmpty() ) {
2614  curUrl = dirUrl;
2615  TQString s =
2616  it.key()->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
2617  if ( s.isEmpty() )
2618  s = it.key()->msgPart().name().stripWhiteSpace().replace( ':', '_' );
2619  if ( s.isEmpty() ) {
2620  ++unnamedAtmCount;
2621  s = i18n("filename for the %1-th unnamed attachment",
2622  "attachment.%1")
2623  .arg( unnamedAtmCount );
2624  }
2625  curUrl.setFileName( s );
2626  } else {
2627  curUrl = url;
2628  }
2629 
2630  if ( !curUrl.isEmpty() ) {
2631 
2632  // Rename the file if we have already saved one with the same name:
2633  // try appending a number before extension (e.g. "pic.jpg" => "pic_2.jpg")
2634  TQString origFile = curUrl.fileName();
2635  TQString file = origFile;
2636 
2637  while ( renameNumbering.contains(file) ) {
2638  file = origFile;
2639  int num = renameNumbering[file] + 1;
2640  int dotIdx = file.findRev('.');
2641  file = file.insert( (dotIdx>=0) ? dotIdx : file.length(), TQString("_") + TQString::number(num) );
2642  }
2643  curUrl.setFileName(file);
2644 
2645  // Increment the counter for both the old and the new filename
2646  if ( !renameNumbering.contains(origFile))
2647  renameNumbering[origFile] = 1;
2648  else
2649  renameNumbering[origFile]++;
2650 
2651  if ( file != origFile ) {
2652  if ( !renameNumbering.contains(file))
2653  renameNumbering[file] = 1;
2654  else
2655  renameNumbering[file]++;
2656  }
2657 
2658 
2659  if ( TDEIO::NetAccess::exists( curUrl, false, parentWidget() ) ) {
2660  if ( KMessageBox::warningContinueCancel( parentWidget(),
2661  i18n( "A file named %1 already exists. Do you want to overwrite it?" )
2662  .arg( curUrl.fileName() ),
2663  i18n( "File Already Exists" ), i18n("&Overwrite") ) == KMessageBox::Cancel) {
2664  continue;
2665  }
2666  }
2667  // save
2668  const Result result = saveItem( it.key(), curUrl );
2669  if ( result != OK )
2670  globalResult = result;
2671  }
2672  }
2673  setResult( globalResult );
2674  emit completed( this );
2675  deleteLater();
2676 }
2677 
2678 KMCommand::Result KMSaveAttachmentsCommand::saveItem( partNode *node,
2679  const KURL& url )
2680 {
2681  bool bSaveEncrypted = false;
2682  bool bEncryptedParts = node->encryptionState() != KMMsgNotEncrypted;
2683  if( bEncryptedParts )
2684  if( KMessageBox::questionYesNo( parentWidget(),
2685  i18n( "The part %1 of the message is encrypted. Do you want to keep the encryption when saving?" ).
2686  arg( url.fileName() ),
2687  i18n( "KMail Question" ), i18n("Keep Encryption"), i18n("Do Not Keep") ) ==
2688  KMessageBox::Yes )
2689  bSaveEncrypted = true;
2690 
2691  bool bSaveWithSig = true;
2692  if( node->signatureState() != KMMsgNotSigned )
2693  if( KMessageBox::questionYesNo( parentWidget(),
2694  i18n( "The part %1 of the message is signed. Do you want to keep the signature when saving?" ).
2695  arg( url.fileName() ),
2696  i18n( "KMail Question" ), i18n("Keep Signature"), i18n("Do Not Keep") ) !=
2697  KMessageBox::Yes )
2698  bSaveWithSig = false;
2699 
2700  TQByteArray data;
2701  if ( mEncoded )
2702  {
2703  // This does not decode the Message Content-Transfer-Encoding
2704  // but saves the _original_ content of the message part
2705  data = KMail::Util::ByteArray( node->msgPart().dwBody() );
2706  }
2707  else
2708  {
2709  if( bSaveEncrypted || !bEncryptedParts) {
2710  partNode *dataNode = node;
2711  TQCString rawReplyString;
2712  bool gotRawReplyString = false;
2713  if( !bSaveWithSig ) {
2714  if( DwMime::kTypeMultipart == node->type() &&
2715  DwMime::kSubtypeSigned == node->subType() ){
2716  // carefully look for the part that is *not* the signature part:
2717  if( node->findType( DwMime::kTypeApplication,
2718  DwMime::kSubtypePgpSignature,
2719  true, false ) ){
2720  dataNode = node->findTypeNot( DwMime::kTypeApplication,
2721  DwMime::kSubtypePgpSignature,
2722  true, false );
2723  }else if( node->findType( DwMime::kTypeApplication,
2724  DwMime::kSubtypePkcs7Mime,
2725  true, false ) ){
2726  dataNode = node->findTypeNot( DwMime::kTypeApplication,
2727  DwMime::kSubtypePkcs7Mime,
2728  true, false );
2729  }else{
2730  dataNode = node->findTypeNot( DwMime::kTypeMultipart,
2731  DwMime::kSubtypeUnknown,
2732  true, false );
2733  }
2734  }else{
2735  ObjectTreeParser otp( 0, 0, false, false, false );
2736 
2737  // process this node and all it's siblings and descendants
2738  dataNode->setProcessed( false, true );
2739  otp.parseObjectTree( dataNode );
2740 
2741  rawReplyString = otp.rawReplyString();
2742  gotRawReplyString = true;
2743  }
2744  }
2745  TQByteArray cstr = gotRawReplyString
2746  ? rawReplyString
2747  : dataNode->msgPart().bodyDecodedBinary();
2748  data = cstr;
2749  size_t size = cstr.size();
2750  if ( dataNode->msgPart().type() == DwMime::kTypeText ) {
2751  // convert CRLF to LF before writing text attachments to disk
2752  size = KMail::Util::crlf2lf( cstr.data(), size );
2753  }
2754  data.resize( size );
2755  }
2756  }
2757  TQDataStream ds;
2758  TQFile file;
2759  KTempFile tf;
2760  tf.setAutoDelete( true );
2761  if ( url.isLocalFile() )
2762  {
2763  // save directly
2764  file.setName( url.path() );
2765  if ( !file.open( IO_WriteOnly ) )
2766  {
2767  KMessageBox::error( parentWidget(),
2768  i18n( "%2 is detailed error description",
2769  "Could not write the file %1:\n%2" )
2770  .arg( file.name() )
2771  .arg( TQString::fromLocal8Bit( strerror( errno ) ) ),
2772  i18n( "KMail Error" ) );
2773  return Failed;
2774  }
2775 
2776  // #79685 by default use the umask the user defined, but let it be configurable
2777  if ( GlobalSettings::self()->disregardUmask() )
2778  fchmod( file.handle(), S_IRUSR | S_IWUSR );
2779 
2780  ds.setDevice( &file );
2781  } else
2782  {
2783  // tmp file for upload
2784  ds.setDevice( tf.file() );
2785  }
2786 
2787  ds.writeRawBytes( data.data(), data.size() );
2788  if ( !url.isLocalFile() )
2789  {
2790  tf.close();
2791  if ( !TDEIO::NetAccess::upload( tf.name(), url, parentWidget() ) )
2792  {
2793  KMessageBox::error( parentWidget(),
2794  i18n( "Could not write the file %1." )
2795  .arg( url.path() ),
2796  i18n( "KMail Error" ) );
2797  return Failed;
2798  }
2799  } else
2800  file.close();
2801  return OK;
2802 }
2803 
2804 KMLoadPartsCommand::KMLoadPartsCommand( TQPtrList<partNode>& parts, KMMessage *msg )
2805  : mNeedsRetrieval( 0 )
2806 {
2807  for ( TQPtrListIterator<partNode> it( parts ); it.current(); ++it ) {
2808  mPartMap.insert( it.current(), msg );
2809  }
2810 }
2811 
2812 KMLoadPartsCommand::KMLoadPartsCommand( partNode *node, KMMessage *msg )
2813  : mNeedsRetrieval( 0 )
2814 {
2815  mPartMap.insert( node, msg );
2816 }
2817 
2818 KMLoadPartsCommand::KMLoadPartsCommand( PartNodeMessageMap& partMap )
2819  : mNeedsRetrieval( 0 ), mPartMap( partMap )
2820 {
2821 }
2822 
2823 void KMLoadPartsCommand::slotStart()
2824 {
2825  for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
2826  it != mPartMap.end();
2827  ++it ) {
2828  if ( !it.key()->msgPart().isComplete() &&
2829  !it.key()->msgPart().partSpecifier().isEmpty() ) {
2830  // incomplete part, so retrieve it first
2831  ++mNeedsRetrieval;
2832  KMFolder* curFolder = it.data()->parent();
2833  if ( curFolder ) {
2834  FolderJob *job =
2835  curFolder->createJob( it.data(), FolderJob::tGetMessage,
2836  0, it.key()->msgPart().partSpecifier() );
2837  job->setCancellable( false );
2838  connect( job, TQT_SIGNAL(messageUpdated(KMMessage*, TQString)),
2839  this, TQT_SLOT(slotPartRetrieved(KMMessage*, TQString)) );
2840  job->start();
2841  } else
2842  kdWarning(5006) << "KMLoadPartsCommand - msg has no parent" << endl;
2843  }
2844  }
2845  if ( mNeedsRetrieval == 0 )
2846  execute();
2847 }
2848 
2849 void KMLoadPartsCommand::slotPartRetrieved( KMMessage *msg,
2850  TQString partSpecifier )
2851 {
2852  DwBodyPart *part =
2853  msg->findDwBodyPart( msg->getFirstDwBodyPart(), partSpecifier );
2854  if ( part ) {
2855  // update the DwBodyPart in the partNode
2856  for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
2857  it != mPartMap.end();
2858  ++it ) {
2859  if ( it.key()->dwPart()->partId() == part->partId() )
2860  it.key()->setDwPart( part );
2861  }
2862  } else
2863  kdWarning(5006) << "KMLoadPartsCommand::slotPartRetrieved - could not find bodypart!" << endl;
2864  --mNeedsRetrieval;
2865  if ( mNeedsRetrieval == 0 )
2866  execute();
2867 }
2868 
2869 KMCommand::Result KMLoadPartsCommand::execute()
2870 {
2871  emit partsRetrieved();
2872  setResult( OK );
2873  emit completed( this );
2874  deleteLater();
2875  return OK;
2876 }
2877 
2878 KMResendMessageCommand::KMResendMessageCommand( TQWidget *parent,
2879  KMMessage *msg )
2880  :KMCommand( parent, msg )
2881 {
2882 }
2883 
2884 KMCommand::Result KMResendMessageCommand::execute()
2885 {
2886  KMMessage *msg = retrievedMessage();
2887  if ( !msg || !msg->codec() ) {
2888  return Failed;
2889  }
2890  KMMessage *newMsg = new KMMessage(*msg);
2891 
2892  TQStringList whiteList;
2893  whiteList << "To" << "Cc" << "Bcc" << "Subject";
2894  newMsg->sanitizeHeaders( whiteList );
2895 
2896  newMsg->setCharset(msg->codec()->mimeName());
2897  newMsg->setParent( 0 );
2898 
2899  // make sure we have an identity set, default, if necessary
2900  newMsg->setHeaderField("X-KMail-Identity", TQString::number( newMsg->identityUoid() ));
2901  newMsg->applyIdentity( newMsg->identityUoid() );
2902 
2903  KMail::Composer * win = KMail::makeComposer();
2904  win->setMsg(newMsg, false, true);
2905  win->show();
2906 
2907  return OK;
2908 }
2909 
2910 KMMailingListCommand::KMMailingListCommand( TQWidget *parent, KMFolder *folder )
2911  : KMCommand( parent ), mFolder( folder )
2912 {
2913 }
2914 
2915 KMCommand::Result KMMailingListCommand::execute()
2916 {
2917  KURL::List lst = urls();
2918  TQString handler = ( mFolder->mailingList().handler() == MailingList::KMail )
2919  ? "mailto" : "https";
2920 
2921  KMCommand *command = 0;
2922  for ( KURL::List::Iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
2923  if ( handler == (*itr).protocol() ) {
2924  command = new KMUrlClickedCommand( *itr, mFolder->identity(), 0, false );
2925  }
2926  }
2927  if ( !command && !lst.empty() ) {
2928  command =
2929  new KMUrlClickedCommand( lst.first(), mFolder->identity(), 0, false );
2930  }
2931  if ( command ) {
2932  connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
2933  this, TQT_SLOT( commandCompleted( KMCommand * ) ) );
2934  setDeletesItself( true );
2935  setEmitsCompletedItself( true );
2936  command->start();
2937  return OK;
2938  }
2939  return Failed;
2940 }
2941 
2942 void KMMailingListCommand::commandCompleted( KMCommand *command )
2943 {
2944  setResult( command->result() );
2945  emit completed( this );
2946  deleteLater();
2947 }
2948 
2949 KMMailingListPostCommand::KMMailingListPostCommand( TQWidget *parent, KMFolder *folder )
2950  : KMMailingListCommand( parent, folder )
2951 {
2952 }
2953 KURL::List KMMailingListPostCommand::urls() const
2954 {
2955  return mFolder->mailingList().postURLS();
2956 }
2957 
2958 KMMailingListSubscribeCommand::KMMailingListSubscribeCommand( TQWidget *parent, KMFolder *folder )
2959  : KMMailingListCommand( parent, folder )
2960 {
2961 }
2962 KURL::List KMMailingListSubscribeCommand::urls() const
2963 {
2964  return mFolder->mailingList().subscribeURLS();
2965 }
2966 
2967 KMMailingListUnsubscribeCommand::KMMailingListUnsubscribeCommand( TQWidget *parent, KMFolder *folder )
2968  : KMMailingListCommand( parent, folder )
2969 {
2970 }
2971 KURL::List KMMailingListUnsubscribeCommand::urls() const
2972 {
2973  return mFolder->mailingList().unsubscribeURLS();
2974 }
2975 
2976 KMMailingListArchivesCommand::KMMailingListArchivesCommand( TQWidget *parent, KMFolder *folder )
2977  : KMMailingListCommand( parent, folder )
2978 {
2979 }
2980 KURL::List KMMailingListArchivesCommand::urls() const
2981 {
2982  return mFolder->mailingList().archiveURLS();
2983 }
2984 
2985 KMMailingListHelpCommand::KMMailingListHelpCommand( TQWidget *parent, KMFolder *folder )
2986  : KMMailingListCommand( parent, folder )
2987 {
2988 }
2989 KURL::List KMMailingListHelpCommand::urls() const
2990 {
2991  return mFolder->mailingList().helpURLS();
2992 }
2993 
2994 KMIMChatCommand::KMIMChatCommand( const KURL &url, KMMessage *msg )
2995  :mUrl( url ), mMessage( msg )
2996 {
2997 }
2998 
2999 KMCommand::Result KMIMChatCommand::execute()
3000 {
3001  kdDebug( 5006 ) << k_funcinfo << " URL is: " << mUrl << endl;
3002  TQString addr = KMMessage::decodeMailtoUrl( mUrl.path() );
3003  // find UID for mail address
3004  TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self( true );
3005  TDEABC::AddresseeList addressees = addressBook->findByEmail( KPIM::getEmailAddress( addr ) ) ;
3006 
3007  // start chat
3008  if( addressees.count() == 1 ) {
3009  kmkernel->imProxy()->chatWithContact( addressees[0].uid() );
3010  return OK;
3011  }
3012  else
3013  {
3014  kdDebug( 5006 ) << "Didn't find exactly one addressee, couldn't tell who to chat to for that email address. Count = " << addressees.count() << endl;
3015 
3016  TQString apology;
3017  if ( addressees.isEmpty() )
3018  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." );
3019  else
3020  {
3021  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." );
3022  TQStringList nameList;
3023  TDEABC::AddresseeList::const_iterator it = addressees.begin();
3024  TDEABC::AddresseeList::const_iterator end = addressees.end();
3025  for ( ; it != end; ++it )
3026  {
3027  nameList.append( (*it).realName() );
3028  }
3029  TQString names = nameList.join( TQString::fromLatin1( ",\n" ) );
3030  apology = apology.arg( names );
3031  }
3032 
3033  KMessageBox::sorry( parentWidget(), apology );
3034  return Failed;
3035  }
3036 }
3037 
3038 KMHandleAttachmentCommand::KMHandleAttachmentCommand( partNode* node,
3039  KMMessage* msg, int atmId, const TQString& atmName,
3040  AttachmentAction action, KService::Ptr offer, TQWidget* parent )
3041 : KMCommand( parent ), mNode( node ), mMsg( msg ), mAtmId( atmId ), mAtmName( atmName ),
3042  mAction( action ), mOffer( offer ), mJob( 0 )
3043 {
3044 }
3045 
3046 void KMHandleAttachmentCommand::slotStart()
3047 {
3048  if ( !mNode->msgPart().isComplete() )
3049  {
3050  // load the part
3051  kdDebug(5006) << "load part" << endl;
3052  KMLoadPartsCommand *command = new KMLoadPartsCommand( mNode, mMsg );
3053  connect( command, TQT_SIGNAL( partsRetrieved() ),
3054  this, TQT_SLOT( slotPartComplete() ) );
3055  command->start();
3056  } else
3057  {
3058  execute();
3059  }
3060 }
3061 
3062 void KMHandleAttachmentCommand::slotPartComplete()
3063 {
3064  execute();
3065 }
3066 
3067 KMCommand::Result KMHandleAttachmentCommand::execute()
3068 {
3069  switch( mAction )
3070  {
3071  case Open:
3072  atmOpen();
3073  break;
3074  case OpenWith:
3075  atmOpenWith();
3076  break;
3077  case View:
3078  atmView();
3079  break;
3080  case Save:
3081  atmSave();
3082  break;
3083  case Properties:
3084  atmProperties();
3085  break;
3086  case ChiasmusEncrypt:
3087  atmEncryptWithChiasmus();
3088  return Undefined;
3089  break;
3090  default:
3091  kdDebug(5006) << "unknown action " << mAction << endl;
3092  break;
3093  }
3094  setResult( OK );
3095  emit completed( this );
3096  deleteLater();
3097  return OK;
3098 }
3099 
3100 TQString KMHandleAttachmentCommand::createAtmFileLink() const
3101 {
3102  TQFileInfo atmFileInfo( mAtmName );
3103 
3104  if ( atmFileInfo.size() == 0 )
3105  {
3106  kdDebug(5006) << k_funcinfo << "rewriting attachment" << endl;
3107  // there is something wrong so write the file again
3108  TQByteArray data = mNode->msgPart().bodyDecodedBinary();
3109  size_t size = data.size();
3110  if ( mNode->msgPart().type() == DwMime::kTypeText && size) {
3111  // convert CRLF to LF before writing text attachments to disk
3112  size = KMail::Util::crlf2lf( data.data(), size );
3113  }
3114  KPIM::kBytesToFile( data.data(), size, mAtmName, false, false, false );
3115  }
3116 
3117  KTempFile *linkFile = new KTempFile( locateLocal("tmp", atmFileInfo.fileName() +"_["),
3118  "]."+ atmFileInfo.extension() );
3119 
3120  linkFile->setAutoDelete(true);
3121  TQString linkName = linkFile->name();
3122  delete linkFile;
3123 
3124  if ( ::link(TQFile::encodeName( mAtmName ), TQFile::encodeName( linkName )) == 0 ) {
3125  return linkName; // success
3126  }
3127  return TQString();
3128 }
3129 
3130 KService::Ptr KMHandleAttachmentCommand::getServiceOffer()
3131 {
3132  KMMessagePart& msgPart = mNode->msgPart();
3133  const TQString contentTypeStr =
3134  ( msgPart.typeStr() + '/' + msgPart.subtypeStr() ).lower();
3135 
3136  if ( contentTypeStr == "text/x-vcard" ) {
3137  atmView();
3138  return 0;
3139  }
3140  // determine the MIME type of the attachment
3141  KMimeType::Ptr mimetype;
3142  // prefer the value of the Content-Type header
3143  mimetype = KMimeType::mimeType( contentTypeStr );
3144  if ( mimetype->name() == "application/octet-stream" ) {
3145  // consider the filename if Content-Type is application/octet-stream
3146  mimetype = KMimeType::findByPath( mAtmName, 0, true /* no disk access */ );
3147  }
3148  if ( ( mimetype->name() == "application/octet-stream" )
3149  && msgPart.isComplete() ) {
3150  // consider the attachment's contents if neither the Content-Type header
3151  // nor the filename give us a clue
3152  mimetype = KMimeType::findByFileContent( mAtmName );
3153  }
3154  return KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
3155 }
3156 
3157 void KMHandleAttachmentCommand::atmOpen()
3158 {
3159  if ( !mOffer )
3160  mOffer = getServiceOffer();
3161  if ( !mOffer ) {
3162  kdDebug(5006) << k_funcinfo << "got no offer" << endl;
3163  return;
3164  }
3165 
3166  KURL::List lst;
3167  KURL url;
3168  bool autoDelete = true;
3169  TQString fname = createAtmFileLink();
3170 
3171  if ( fname.isNull() ) {
3172  autoDelete = false;
3173  fname = mAtmName;
3174  }
3175 
3176  url.setPath( fname );
3177  lst.append( url );
3178  if ( (KRun::run( *mOffer, lst, autoDelete ) <= 0) && autoDelete ) {
3179  TQFile::remove(url.path());
3180  }
3181 }
3182 
3183 void KMHandleAttachmentCommand::atmOpenWith()
3184 {
3185  KURL::List lst;
3186  KURL url;
3187  bool autoDelete = true;
3188  TQString fname = createAtmFileLink();
3189 
3190  if ( fname.isNull() ) {
3191  autoDelete = false;
3192  fname = mAtmName;
3193  }
3194 
3195  url.setPath( fname );
3196  lst.append( url );
3197  if ( (! KRun::displayOpenWithDialog(lst, autoDelete)) && autoDelete ) {
3198  TQFile::remove( url.path() );
3199  }
3200 }
3201 
3202 void KMHandleAttachmentCommand::atmView()
3203 {
3204  // we do not handle this ourself
3205  emit showAttachment( mAtmId, mAtmName );
3206 }
3207 
3208 void KMHandleAttachmentCommand::atmSave()
3209 {
3210  TQPtrList<partNode> parts;
3211  parts.append( mNode );
3212  // save, do not leave encoded
3213  KMSaveAttachmentsCommand *command =
3214  new KMSaveAttachmentsCommand( parentWidget(), parts, mMsg, false );
3215  command->start();
3216 }
3217 
3218 void KMHandleAttachmentCommand::atmProperties()
3219 {
3220  KMMsgPartDialogCompat dlg( parentWidget() , 0, true );
3221  KMMessagePart& msgPart = mNode->msgPart();
3222  dlg.setMsgPart( &msgPart );
3223  dlg.exec();
3224 }
3225 
3226 void KMHandleAttachmentCommand::atmEncryptWithChiasmus()
3227 {
3228  const partNode * node = mNode;
3229  Q_ASSERT( node );
3230  if ( !node )
3231  return;
3232 
3233  // FIXME: better detection of mimetype??
3234  if ( !mAtmName.endsWith( ".xia", false ) )
3235  return;
3236 
3237  const Kleo::CryptoBackend::Protocol * chiasmus =
3238  Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
3239  Q_ASSERT( chiasmus );
3240  if ( !chiasmus )
3241  return;
3242 
3243  const STD_NAMESPACE_PREFIX auto_ptr<Kleo::SpecialJob> listjob( chiasmus->specialJob( "x-obtain-keys", TQMap<TQString,TQVariant>() ) );
3244  if ( !listjob.get() ) {
3245  const TQString msg = i18n( "Chiasmus backend does not offer the "
3246  "\"x-obtain-keys\" function. Please report this bug." );
3247  KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3248  return;
3249  }
3250 
3251  if ( listjob->exec() ) {
3252  listjob->showErrorDialog( parentWidget(), i18n( "Chiasmus Backend Error" ) );
3253  return;
3254  }
3255 
3256  const TQVariant result = listjob->property( "result" );
3257  if ( result.type() != TQVariant::StringList ) {
3258  const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
3259  "The \"x-obtain-keys\" function did not return a "
3260  "string list. Please report this bug." );
3261  KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3262  return;
3263  }
3264 
3265  const TQStringList keys = result.toStringList();
3266  if ( keys.empty() ) {
3267  const TQString msg = i18n( "No keys have been found. Please check that a "
3268  "valid key path has been set in the Chiasmus "
3269  "configuration." );
3270  KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3271  return;
3272  }
3273 
3274  ChiasmusKeySelector selectorDlg( parentWidget(), i18n( "Chiasmus Decryption Key Selection" ),
3275  keys, GlobalSettings::chiasmusDecryptionKey(),
3276  GlobalSettings::chiasmusDecryptionOptions() );
3277  if ( selectorDlg.exec() != TQDialog::Accepted )
3278  return;
3279 
3280  GlobalSettings::setChiasmusDecryptionOptions( selectorDlg.options() );
3281  GlobalSettings::setChiasmusDecryptionKey( selectorDlg.key() );
3282  assert( !GlobalSettings::chiasmusDecryptionKey().isEmpty() );
3283 
3284  Kleo::SpecialJob * job = chiasmus->specialJob( "x-decrypt", TQMap<TQString,TQVariant>() );
3285  if ( !job ) {
3286  const TQString msg = i18n( "Chiasmus backend does not offer the "
3287  "\"x-decrypt\" function. Please report this bug." );
3288  KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3289  return;
3290  }
3291 
3292  const TQByteArray input = node->msgPart().bodyDecodedBinary();
3293 
3294  if ( !job->setProperty( "key", GlobalSettings::chiasmusDecryptionKey() ) ||
3295  !job->setProperty( "options", GlobalSettings::chiasmusDecryptionOptions() ) ||
3296  !job->setProperty( "input", input ) ) {
3297  const TQString msg = i18n( "The \"x-decrypt\" function does not accept "
3298  "the expected parameters. Please report this bug." );
3299  KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3300  return;
3301  }
3302 
3303  setDeletesItself( true ); // the job below is async, we have to cleanup ourselves
3304  if ( job->start() ) {
3305  job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
3306  return;
3307  }
3308 
3309  mJob = job;
3310  connect( job, TQT_SIGNAL(result(const GpgME::Error&,const TQVariant&)),
3311  this, TQT_SLOT(slotAtmDecryptWithChiasmusResult(const GpgME::Error&,const TQVariant&)) );
3312 }
3313 
3314 static const TQString chomp( const TQString & base, const TQString & suffix, bool cs ) {
3315  return base.endsWith( suffix, cs ) ? base.left( base.length() - suffix.length() ) : base ;
3316 }
3317 
3318 void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusResult( const GpgME::Error & err, const TQVariant & result )
3319 {
3320  LaterDeleterWithCommandCompletion d( this );
3321  if ( !mJob )
3322  return;
3323  Q_ASSERT( mJob == sender() );
3324  if ( mJob != sender() )
3325  return;
3326  Kleo::Job * job = mJob;
3327  mJob = 0;
3328  if ( err.isCanceled() )
3329  return;
3330  if ( err ) {
3331  job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
3332  return;
3333  }
3334 
3335  if ( result.type() != TQVariant::ByteArray ) {
3336  const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
3337  "The \"x-decrypt\" function did not return a "
3338  "byte array. Please report this bug." );
3339  KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
3340  return;
3341  }
3342 
3343  const KURL url = KFileDialog::getSaveURL( chomp( mAtmName, ".xia", false ), TQString(), parentWidget() );
3344  if ( url.isEmpty() )
3345  return;
3346 
3347  bool overwrite = KMail::Util::checkOverwrite( url, parentWidget() );
3348  if ( !overwrite )
3349  return;
3350 
3351  d.setDisabled( true ); // we got this far, don't delete yet
3352  TDEIO::Job * uploadJob = TDEIO::storedPut( result.toByteArray(), url, -1, overwrite, false /*resume*/ );
3353  uploadJob->setWindow( parentWidget() );
3354  connect( uploadJob, TQT_SIGNAL(result(TDEIO::Job*)),
3355  this, TQT_SLOT(slotAtmDecryptWithChiasmusUploadResult(TDEIO::Job*)) );
3356 }
3357 
3358 void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusUploadResult( TDEIO::Job * job )
3359 {
3360  if ( job->error() )
3361  job->showErrorDialog();
3362  LaterDeleterWithCommandCompletion d( this );
3363  d.setResult( OK );
3364 }
3365 
3366 
3367 AttachmentModifyCommand::AttachmentModifyCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
3368  KMCommand( parent, msg ),
3369  mPartIndex( node->nodeId() ),
3370  mSernum( 0 )
3371 {
3372 }
3373 
3374 AttachmentModifyCommand::AttachmentModifyCommand( int nodeId, KMMessage *msg, TQWidget *parent )
3375  : KMCommand( parent, msg ),
3376  mPartIndex( nodeId ),
3377  mSernum( 0 )
3378 {
3379 }
3380 
3381 AttachmentModifyCommand::~ AttachmentModifyCommand()
3382 {
3383 }
3384 
3385 KMCommand::Result AttachmentModifyCommand::execute()
3386 {
3387  KMMessage *msg = retrievedMessage();
3388  if ( !msg )
3389  return Failed;
3390  mSernum = msg->getMsgSerNum();
3391 
3392  mFolder = msg->parent();
3393  if ( !mFolder || !mFolder->storage() )
3394  return Failed;
3395 
3396  Result res = doAttachmentModify();
3397  if ( res != OK )
3398  return res;
3399 
3400  setEmitsCompletedItself( true );
3401  setDeletesItself( true );
3402  return OK;
3403 }
3404 
3405 void AttachmentModifyCommand::storeChangedMessage(KMMessage * msg)
3406 {
3407  if ( !mFolder || !mFolder->storage() ) {
3408  kdWarning(5006) << k_funcinfo << "We lost the folder!" << endl;
3409  setResult( Failed );
3410  emit completed( this );
3411  deleteLater();
3412  }
3413  int res = mFolder->addMsg( msg ) != 0;
3414  if ( mFolder->folderType() == KMFolderTypeImap ) {
3415  KMFolderImap *f = static_cast<KMFolderImap*>( mFolder->storage() );
3416  connect( f, TQT_SIGNAL(folderComplete(KMFolderImap*,bool)),
3417  TQT_SLOT(messageStoreResult(KMFolderImap*,bool)) );
3418  } else {
3419  messageStoreResult( 0, res == 0 );
3420  }
3421 }
3422 
3423 void AttachmentModifyCommand::messageStoreResult(KMFolderImap* folder, bool success )
3424 {
3425  Q_UNUSED( folder );
3426  if ( success ) {
3427  KMCommand *delCmd = new KMDeleteMsgCommand( mSernum );
3428  connect( delCmd, TQT_SIGNAL(completed(KMCommand*)), TQT_SLOT(messageDeleteResult(KMCommand*)) );
3429  delCmd->start();
3430  return;
3431  }
3432  kdWarning(5006) << k_funcinfo << "Adding modified message failed." << endl;
3433  setResult( Failed );
3434  emit completed( this );
3435  deleteLater();
3436 }
3437 
3438 void AttachmentModifyCommand::messageDeleteResult(KMCommand * cmd)
3439 {
3440  setResult( cmd->result() );
3441  emit completed( this );
3442  deleteLater();
3443 }
3444 
3445 KMDeleteAttachmentCommand::KMDeleteAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
3446  AttachmentModifyCommand( node, msg, parent )
3447 {
3448  kdDebug(5006) << k_funcinfo << endl;
3449 }
3450 
3451 KMDeleteAttachmentCommand::KMDeleteAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent )
3452  : AttachmentModifyCommand( nodeId, msg, parent )
3453 {
3454  kdDebug(5006) << k_funcinfo << endl;
3455 }
3456 
3457 KMDeleteAttachmentCommand::~KMDeleteAttachmentCommand()
3458 {
3459  kdDebug(5006) << k_funcinfo << endl;
3460 }
3461 
3462 KMCommand::Result KMDeleteAttachmentCommand::doAttachmentModify()
3463 {
3464  KMMessage *msg = retrievedMessage();
3465  if ( !msg || !msg->deleteBodyPart( mPartIndex ) )
3466  return Failed;
3467 
3468  KMMessage *newMsg = new KMMessage();
3469  newMsg->fromDwString( msg->asDwString() );
3470  newMsg->setStatus( msg->status() );
3471 
3472  storeChangedMessage( newMsg );
3473  return OK;
3474 }
3475 
3476 
3477 KMEditAttachmentCommand::KMEditAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
3478  AttachmentModifyCommand( node, msg, parent )
3479 {
3480  kdDebug(5006) << k_funcinfo << endl;
3481  mTempFile.setAutoDelete( true );
3482 }
3483 
3484 KMEditAttachmentCommand::KMEditAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent )
3485  : AttachmentModifyCommand( nodeId, msg, parent )
3486 {
3487  kdDebug(5006) << k_funcinfo << endl;
3488  mTempFile.setAutoDelete( true );
3489 }
3490 
3491 KMEditAttachmentCommand::~ KMEditAttachmentCommand()
3492 {
3493 }
3494 
3495 KMCommand::Result KMEditAttachmentCommand::doAttachmentModify()
3496 {
3497  KMMessage *msg = retrievedMessage();
3498  if ( !msg )
3499  return Failed;
3500 
3501  KMMessagePart part;
3502  DwBodyPart *dwpart = msg->findPart( mPartIndex );
3503  if ( !dwpart )
3504  return Failed;
3505  KMMessage::bodyPart( dwpart, &part, true );
3506  if ( !part.isComplete() )
3507  return Failed;
3508 
3509  if( !dynamic_cast<DwBody*>( dwpart->Parent() ) )
3510  return Failed;
3511 
3512  mTempFile.file()->writeBlock( part.bodyDecodedBinary() );
3513  mTempFile.file()->flush();
3514 
3515  KMail::EditorWatcher *watcher =
3516  new KMail::EditorWatcher( KURL( mTempFile.file()->name() ),
3517  part.typeStr() + "/" + part.subtypeStr(),
3518  false, this, parentWidget() );
3519  connect( watcher, TQT_SIGNAL(editDone(KMail::EditorWatcher*)), TQT_SLOT(editDone(KMail::EditorWatcher*)) );
3520  if ( !watcher->start() )
3521  return Failed;
3522  setEmitsCompletedItself( true );
3523  setDeletesItself( true );
3524  return OK;
3525 }
3526 
3527 void KMEditAttachmentCommand::editDone(KMail::EditorWatcher * watcher)
3528 {
3529  kdDebug(5006) << k_funcinfo << endl;
3530  // anything changed?
3531  if ( !watcher->fileChanged() ) {
3532  kdDebug(5006) << k_funcinfo << "File has not been changed" << endl;
3533  setResult( Canceled );
3534  emit completed( this );
3535  deleteLater();
3536  }
3537 
3538  mTempFile.file()->reset();
3539  TQByteArray data = mTempFile.file()->readAll();
3540 
3541  // build the new message
3542  KMMessage *msg = retrievedMessage();
3543  KMMessagePart part;
3544  DwBodyPart *dwpart = msg->findPart( mPartIndex );
3545  KMMessage::bodyPart( dwpart, &part, true );
3546 
3547  DwBody *parentNode = dynamic_cast<DwBody*>( dwpart->Parent() );
3548  assert( parentNode );
3549  parentNode->RemoveBodyPart( dwpart );
3550 
3551  KMMessagePart att;
3552  att.duplicate( part );
3553  att.setBodyEncodedBinary( data );
3554 
3555  DwBodyPart* newDwPart = msg->createDWBodyPart( &att );
3556  parentNode->AddBodyPart( newDwPart );
3557  msg->getTopLevelPart()->Assemble();
3558 
3559  KMMessage *newMsg = new KMMessage();
3560  newMsg->fromDwString( msg->asDwString() );
3561  newMsg->setStatus( msg->status() );
3562 
3563  storeChangedMessage( newMsg );
3564 }
3565 
3566 
3567 CreateTodoCommand::CreateTodoCommand(TQWidget * parent, KMMessage * msg)
3568  : KMCommand( parent, msg )
3569 {
3570 }
3571 
3572 KMCommand::Result CreateTodoCommand::execute()
3573 {
3574  KMMessage *msg = retrievedMessage();
3575  if ( !msg || !msg->codec() ) {
3576  return Failed;
3577  }
3578 
3579  KMail::KorgHelper::ensureRunning();
3580 
3581  TQString txt = i18n("From: %1\nTo: %2\nSubject: %3").arg( msg->from() )
3582  .arg( msg->to() ).arg( msg->subject() );
3583 
3584  KTempFile tf;
3585  tf.setAutoDelete( true );
3586  TQString uri = "kmail:" + TQString::number( msg->getMsgSerNum() ) + "/" + msg->msgId();
3587  tf.file()->writeBlock( msg->asDwString().c_str(), msg->asDwString().length() );
3588  tf.close();
3589 
3590  KCalendarIface_stub *iface = new KCalendarIface_stub( kapp->dcopClient(), "korganizer", "CalendarIface" );
3591  iface->openTodoEditor( i18n("Mail: %1").arg( msg->subject() ), txt, uri,
3592  tf.name(), TQStringList(), "message/rfc822", true );
3593  delete iface;
3594 
3595  return OK;
3596 }
3597 
3598 #include "kmcommands.moc"
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 noContent() const
Returns, if the folder can&#39;t contain mails, but only subfolder.
Definition: kmfolder.cpp:301
virtual TQString prettyURL() const
URL of the node for visualization purposes.
TQString subject() const
Get or set the &#39;Subject&#39; header field.
Definition: kmmessage.cpp:2052
TQString from() const
Get or set the &#39;From&#39; header field.
Definition: kmmessage.cpp:2018
virtual TQString prettyURL() const
URL of the node for visualization purposes.
Definition: kmfolder.cpp:593
const KMMsgBase * getMsgBase(int idx) const
Provides access to the basic message fields that are also stored in the index.
Definition: kmfolder.cpp:360
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.
void setStatus(const KMMsgStatus status, int idx=-1)
Set status and mark dirty.
Definition: kmmessage.cpp:4153
const TQTextCodec * codec() const
Get a TQTextCodec suitable for this message part.
Definition: kmmessage.cpp:4453
void applyIdentity(uint id)
Set the from, to, cc, bcc, encrytion etc headers as specified in the given identity.
Definition: kmmessage.cpp:1665
TQString msgId() const
Get or set the &#39;Message-Id&#39; header field.
Definition: kmmessage.cpp:2185
This class implements a "reader window", that is a window used for reading or viewing messages...
Definition: kmreaderwin.h:76
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:1745
void initHeader(uint identity=0)
Initialize header fields.
Definition: kmmessage.cpp:1718
A LaterDeleter is intended to be used with the RAII ( Resource Acquisition is Initialization ) paradi...
Definition: util.h:179
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
KMMessage * take(int idx)
Detach message from this folder.
Definition: kmfolder.cpp:380
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
int find(const KMMsgBase *msg) const
Returns the index of the given message or -1 if not found.
Definition: kmfolder.cpp:435
uint identityUoid() const
Definition: kmmessage.cpp:1730
KMMsgBase & toMsgBase()
Get KMMsgBase for this object.
Definition: kmmessage.h:115
void setBody(const TQCString &aStr)
Set the message body.
Definition: kmmessage.cpp:2777
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Definition: kmmsgdict.cpp:167
This class encapsulates the visual appearance of message headers.
Definition: headerstyle.h:51
void setCharset(const TQCString &charset, DwEntity *entity=0)
Sets the charset of the message or a subpart of the message.
Definition: kmmessage.cpp:4114
static void bodyPart(DwBodyPart *aDwBodyPart, KMMessagePart *aPart, bool withBody=true)
Fill the KMMessagePart structure for a given DwBodyPart.
Definition: kmmessage.cpp:3108
DwBodyPart * getFirstDwBodyPart() const
Get the 1st DwBodyPart.
Definition: kmmessage.cpp:2851
bool isReadOnly() const
Is the folder read-only?
Definition: kmfolder.cpp:561
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:2342
KMMsgStatus status() const
Status of the message.
Definition: kmmessage.h:831
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
Definition: kmmessage.cpp:2292
DwBodyPart * createDWBodyPart(const KMMessagePart *aPart)
Compose a DwBodyPart (needed for adding a part to the message).
Definition: kmmessage.cpp:3218
void setComplete(bool v)
Set if the message is a complete message.
Definition: kmmessage.h:870
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:866
The widget that shows the contents of folders.
Definition: kmheaders.h:48
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
void removePrivateHeaderFields()
Remove all private header fields: *Status: and X-KMail-*.
Definition: kmmessage.cpp:338
bool deleteBodyPart(int partIndex)
Delete a body part with the specified part index.
Definition: kmmessage.cpp:3181
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
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
KMail message redirection dialog.
bool transferInProgress() const
Return, if the message should not be deleted.
Definition: kmmessage.cpp:239
Window class for secondary KMail window like the composer window and the separate message window...
void setReadyToShow(bool v)
Set if the message is ready to be shown.
Definition: kmmessage.h:875
TQString headerAsString() const
Return header as string.
Definition: kmmessage.cpp:381
Mail folder.
Definition: kmfolder.h:68
void setStatus(int idx, KMMsgStatus status, bool toggle=false)
Set the status of the message at index idx to status.
Definition: kmfolder.cpp:831
Base class for commands modifying attachements of existing messages.
Definition: kmcommands.h:1093
TQCString body() const
Get the message body.
Definition: kmmessage.cpp:2573
KMail list that manages the contents of one directory that may contain folders and/or other directori...
Definition: kmfolderdir.h:15
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:1134
bool isMessage(int idx)
Checks if the message is already "gotten" with getMsg.
Definition: kmfolder.cpp:331
bool isComplete() const
Return true if the complete message is available without referring to the backing store...
Definition: kmmessage.h:868
void fromDwString(const DwString &str, bool setStatus=false)
Parse the string and create this message from it.
Definition: kmmessage.cpp:405
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:1232
virtual TQString label() const
Returns the label of the folder for visualization.
Definition: kmfolder.cpp:581
TQString to() const
Get or set the &#39;To&#39; header field.
Definition: kmmessage.cpp:1897
TQCString asString() const
Return the entire message contents as a string.
Definition: kmmessage.cpp:317
Starts an editor for the given URL and emits an signal when editing has been finished.
Definition: editorwatcher.h:38
static TQString decodeMailtoUrl(const TQString &url)
Decodes a mailto URL.
Definition: kmmessage.cpp:3473
KMMessage * getMsg(int idx)
Read message at given index.
Definition: kmfolder.cpp:321
sets a cursor and makes sure it&#39;s restored on destruction Create a KCursorSaver object when you want ...
Definition: kcursorsaver.h:13
void sanitizeHeaders(const TQStringList &whiteList=TQStringList())
Remove all headers but the content description ones, and those in the white list. ...
Definition: kmmessage.cpp:1213
DwBodyPart * findDwBodyPart(int type, int subtype) const
Return the first DwBodyPart matching a given Content-Type or zero, if no found.
Definition: kmmessage.cpp:2938
TQByteArray ByteArray(const DwString &str)
Construct a TQByteArray from a DwString.
Definition: util.cpp:122
bool isOpened() const
Test if folder is opened.
Definition: kmfolder.cpp:500
folderdiaquotatab.h
Definition: aboutdata.cpp:40
void close(const char *owner, bool force=false)
Close folder.
Definition: kmfolder.cpp:489
TQCString charset() const
Get the message charset.
Definition: kmmessage.cpp:4098
This is a Mime Message.
Definition: kmmessage.h:68
TQCString mboxMessageSeparator()
Returns an mbox message separator line for this message, i.e.
Definition: kmmessage.cpp:4481
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
Definition: kmmessage.cpp:246
void removeHeaderField(const TQCString &name)
Remove header field with given name.
Definition: kmmessage.cpp:2320
int open(const char *owner)
Open folder for access.
Definition: kmfolder.cpp:479
KMMsgInfo * unGetMsg(int idx)
Replace KMMessage with KMMsgInfo and delete KMMessage.
Definition: kmfolder.cpp:326
Visual representation of a member of the set of displayables (mails in the current folder)...
Definition: headeritem.h:163
void link(const KMMessage *aMsg, KMMsgStatus aStatus)
Links this message to aMsg, setting link type to aStatus.
Definition: kmmessage.cpp:4190
The attachment dialog with convenience backward compatible methods.
Definition: kmmsgpartdlg.h:141
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:1780
KMFolder * trashFolder() const
If this folder has a special trash folder set, return it.
Definition: kmfolder.cpp:821
const DwString & asDwString() const
Return the entire message contents in the DwString.
Definition: kmmessage.cpp:295
size_t msgSizeServer() const
Get/set size on server.
Definition: kmmessage.cpp:2215