kmail Library API Documentation

kmcommands.cpp

00001 // -*- mode: C++; c-file-style: "gnu" -*- 00002 // kmcommands 00003 // (c) 2002 Don Sanders <sanders@kde.org> 00004 // License: GPL 00005 // 00006 // This file implements various "command" classes. These command classes 00007 // are based on the command design pattern. 00008 // 00009 // Historically various operations were implemented as slots of KMMainWin. 00010 // This proved inadequate as KMail has multiple top level windows 00011 // (KMMainWin, KMReaderMainWin, KMFldSearch, KMComposeWin) that may 00012 // benefit from using these operations. It is desirable that these 00013 // classes can operate without depending on or altering the state of 00014 // a KMMainWin, in fact it is possible no KMMainWin object even exists. 00015 // 00016 // Now these operations have been rewritten as KMCommand based classes, 00017 // making them independent of KMMainWin. 00018 // 00019 // The base command class KMCommand is async, which is a difference 00020 // from the conventional command pattern. As normal derived classes implement 00021 // the execute method, but client classes call start() instead of 00022 // calling execute() directly. start() initiates async operations, 00023 // and on completion of these operations calls execute() and then deletes 00024 // the command. (So the client must not construct commands on the stack). 00025 // 00026 // The type of async operation supported by KMCommand is retrieval 00027 // of messages from an IMAP server. 00028 #ifdef HAVE_CONFIG_H 00029 #include <config.h> 00030 #endif 00031 00032 #include <errno.h> 00033 #include <mimelib/enum.h> 00034 #include <mimelib/field.h> 00035 #include <mimelib/mimepp.h> 00036 00037 #include <qtextcodec.h> 00038 00039 #include <kdebug.h> 00040 #include <kfiledialog.h> 00041 #include <kio/netaccess.h> 00042 #include <klocale.h> 00043 #include <kmessagebox.h> 00044 #include <kparts/browserextension.h> 00045 #include <kprogress.h> 00046 #include <krun.h> 00047 #include <kbookmarkmanager.h> 00048 #include <kstandarddirs.h> 00049 #include "actionscheduler.h" 00050 using KMail::ActionScheduler; 00051 #include "mailinglist-magic.h" 00052 #include "kmaddrbook.h" 00053 #include "kmcomposewin.h" 00054 #include "kmfiltermgr.h" 00055 #include "kmfolderimap.h" 00056 #include "kmfoldermgr.h" 00057 #include "kmheaders.h" 00058 #include "kmmainwidget.h" 00059 #include "kmmsgdict.h" 00060 #include "kmsender.h" 00061 #include "undostack.h" 00062 #include "partNode.h" 00063 #include "kcursorsaver.h" 00064 #include "partNode.h" 00065 using KMail::FolderJob; 00066 #include "mailsourceviewer.h" 00067 using KMail::MailSourceViewer; 00068 00069 #include "kmcommands.h" 00070 #include "kmcommands.moc" 00071 00072 KMCommand::KMCommand( QWidget *parent ) 00073 : mProgressDialog( 0 ), mDeletesItself( false ), mParent( parent ) 00074 { 00075 } 00076 00077 KMCommand::KMCommand( QWidget *parent, const QPtrList<KMMsgBase> &msgList ) 00078 : mProgressDialog( 0 ), mDeletesItself( false ), mParent( parent ), mMsgList( msgList ) 00079 { 00080 } 00081 00082 KMCommand::KMCommand( QWidget *parent, KMMsgBase *msgBase ) 00083 : mProgressDialog( 0 ), mDeletesItself( false ), mParent( parent ) 00084 { 00085 mMsgList.append( msgBase ); 00086 } 00087 00088 KMCommand::KMCommand( QWidget *parent, KMMessage *msg ) 00089 : mProgressDialog( 0 ), mDeletesItself( false ), mParent( parent ) 00090 { 00091 mMsgList.append( &msg->toMsgBase() ); 00092 } 00093 00094 KMCommand::~KMCommand() 00095 { 00096 QValueListIterator<QGuardedPtr<KMFolder> > fit; 00097 for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) { 00098 if (!(*fit)) 00099 continue; 00100 (*fit)->close(); 00101 } 00102 } 00103 00104 void KMCommand::start() 00105 { 00106 preTransfer(); 00107 } 00108 00109 00110 const QPtrList<KMMessage> KMCommand::retrievedMsgs() const 00111 { 00112 return mRetrievedMsgs; 00113 } 00114 00115 KMMessage *KMCommand::retrievedMessage() const 00116 { 00117 return mRetrievedMsgs.getFirst(); 00118 } 00119 00120 int KMCommand::mCountJobs = 0; 00121 00122 void KMCommand::preTransfer() 00123 { 00124 connect(this, SIGNAL(messagesTransfered(bool)), 00125 this, SLOT(slotPostTransfer(bool))); 00126 kmkernel->filterMgr()->ref(); 00127 00128 if (mMsgList.find(0) != -1) { 00129 emit messagesTransfered(false); 00130 return; 00131 } 00132 00133 if ((mMsgList.count() == 1) && 00134 (mMsgList.getFirst()->isMessage()) && 00135 (mMsgList.getFirst()->parent() == 0)) 00136 { 00137 // Special case of operating on message that isn't in a folder 00138 mRetrievedMsgs.append((KMMessage*)mMsgList.getFirst()); 00139 emit messagesTransfered(true); 00140 return; 00141 } 00142 00143 for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next()) 00144 if (!mb->parent()) { 00145 emit messagesTransfered(false); 00146 return; 00147 } else { 00148 mFolders.append( mb->parent() ); 00149 mb->parent()->open(); 00150 } 00151 00152 // transfer the selected messages first 00153 transferSelectedMsgs(); 00154 } 00155 00156 void KMCommand::slotPostTransfer(bool success) 00157 { 00158 disconnect(this, SIGNAL(messagesTransfered(bool)), 00159 this, SLOT(slotPostTransfer(bool))); 00160 if (success) 00161 execute(); 00162 QPtrListIterator<KMMessage> it( mRetrievedMsgs ); 00163 KMMessage* msg; 00164 while ( (msg = it.current()) != 0 ) 00165 { 00166 ++it; 00167 if (msg->parent()) 00168 msg->setTransferInProgress(false); 00169 } 00170 kmkernel->filterMgr()->deref(); 00171 if ( !deletesItself() ) 00172 delete this; 00173 } 00174 00175 void KMCommand::transferSelectedMsgs() 00176 { 00177 // make sure no other transfer is active 00178 if (KMCommand::mCountJobs > 0) { 00179 emit messagesTransfered(false); 00180 return; 00181 } 00182 00183 bool complete = true; 00184 KMCommand::mCountJobs = 0; 00185 mCountMsgs = 0; 00186 mRetrievedMsgs.clear(); 00187 mCountMsgs = mMsgList.count(); 00188 // the KProgressDialog for the user-feedback. Only enable it if it's needed. 00189 // For some commands like KMSetStatusCommand it's not needed. Note, that 00190 // for some reason the KProgressDialog eats the MouseReleaseEvent (if a 00191 // command is executed after the MousePressEvent), cf. bug #71761. 00192 if ( mCountMsgs > 0 ) { 00193 mProgressDialog = new KProgressDialog(mParent, "transferProgress", 00194 i18n("Please wait"), 00195 i18n("Please wait while the message is transferred", 00196 "Please wait while the %n messages are transferred", mMsgList.count()), 00197 true); 00198 mProgressDialog->setMinimumDuration(1000); 00199 } 00200 for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next()) 00201 { 00202 // check if all messages are complete 00203 KMMessage *thisMsg = 0; 00204 if ( mb->isMessage() ) 00205 thisMsg = static_cast<KMMessage*>(mb); 00206 else 00207 { 00208 KMFolder *folder = mb->parent(); 00209 int idx = folder->find(mb); 00210 if (idx < 0) continue; 00211 thisMsg = folder->getMsg(idx); 00212 } 00213 if (!thisMsg) continue; 00214 if ( thisMsg->transferInProgress() && 00215 thisMsg->parent()->folderType() == KMFolderTypeImap ) 00216 { 00217 thisMsg->setTransferInProgress( false, true ); 00218 thisMsg->parent()->ignoreJobsForMessage( thisMsg ); 00219 } 00220 00221 if ( thisMsg->parent() && !thisMsg->isComplete() && 00222 ( !mProgressDialog || !mProgressDialog->wasCancelled() ) ) 00223 { 00224 kdDebug(5006)<<"### INCOMPLETE with protocol = "<<thisMsg->parent()->protocol() <<endl; 00225 // the message needs to be transferred first 00226 complete = false; 00227 KMCommand::mCountJobs++; 00228 FolderJob *job = thisMsg->parent()->createJob(thisMsg); 00229 // emitted when the message was transferred successfully 00230 connect(job, SIGNAL(messageRetrieved(KMMessage*)), 00231 this, SLOT(slotMsgTransfered(KMMessage*))); 00232 // emitted when the job is destroyed 00233 connect(job, SIGNAL(finished()), 00234 this, SLOT(slotJobFinished())); 00235 // msg musn't be deleted 00236 thisMsg->setTransferInProgress(true); 00237 job->start(); 00238 } else { 00239 thisMsg->setTransferInProgress(true); 00240 mRetrievedMsgs.append(thisMsg); 00241 } 00242 } 00243 00244 if (complete) 00245 { 00246 delete mProgressDialog; 00247 emit messagesTransfered(true); 00248 } else { 00249 // wait for the transfer and tell the progressBar the necessary steps 00250 if ( mProgressDialog ) { 00251 connect(mProgressDialog, SIGNAL(cancelClicked()), 00252 this, SLOT(slotTransferCancelled())); 00253 mProgressDialog->progressBar()->setTotalSteps(KMCommand::mCountJobs); 00254 } 00255 } 00256 } 00257 00258 void KMCommand::slotMsgTransfered(KMMessage* msg) 00259 { 00260 if ( mProgressDialog && mProgressDialog->wasCancelled() ) { 00261 emit messagesTransfered(false); 00262 return; 00263 } 00264 00265 // save the complete messages 00266 mRetrievedMsgs.append(msg); 00267 } 00268 00269 void KMCommand::slotJobFinished() 00270 { 00271 // the job is finished (with / without error) 00272 KMCommand::mCountJobs--; 00273 00274 if ( mProgressDialog && mProgressDialog->wasCancelled() ) return; 00275 00276 if ( (mCountMsgs - static_cast<int>(mRetrievedMsgs.count())) > KMCommand::mCountJobs ) 00277 { 00278 // the message wasn't retrieved before => error 00279 if ( mProgressDialog ) 00280 mProgressDialog->hide(); 00281 slotTransferCancelled(); 00282 return; 00283 } 00284 // update the progressbar 00285 if ( mProgressDialog ) { 00286 mProgressDialog->progressBar()->advance(1); 00287 mProgressDialog->setLabel(i18n("Please wait while the message is transferred", 00288 "Please wait while the %n messages are transferred", KMCommand::mCountJobs)); 00289 } 00290 if (KMCommand::mCountJobs == 0) 00291 { 00292 // all done 00293 delete mProgressDialog; 00294 emit messagesTransfered(true); 00295 } 00296 } 00297 00298 void KMCommand::slotTransferCancelled() 00299 { 00300 // kill the pending jobs 00301 QValueListIterator<QGuardedPtr<KMFolder> > fit; 00302 for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) { 00303 if (!(*fit)) 00304 continue; 00305 KMFolder *folder = *fit; 00306 KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder); 00307 if (imapFolder && imapFolder->account()) { 00308 imapFolder->account()->killAllJobs(); 00309 imapFolder->account()->setIdle(true); 00310 } 00311 } 00312 00313 KMCommand::mCountJobs = 0; 00314 mCountMsgs = 0; 00315 // unget the transfered messages 00316 QPtrListIterator<KMMessage> it( mRetrievedMsgs ); 00317 KMMessage* msg; 00318 while ( (msg = it.current()) != 0 ) 00319 { 00320 KMFolder *folder = msg->parent(); 00321 ++it; 00322 if (!folder) 00323 continue; 00324 msg->setTransferInProgress(false); 00325 int idx = folder->find(msg); 00326 if (idx > 0) folder->unGetMsg(idx); 00327 } 00328 mRetrievedMsgs.clear(); 00329 emit messagesTransfered(false); 00330 } 00331 00332 KMMailtoComposeCommand::KMMailtoComposeCommand( const KURL &url, 00333 KMMessage *msg ) 00334 :mUrl( url ), mMessage( msg ) 00335 { 00336 } 00337 00338 void KMMailtoComposeCommand::execute() 00339 { 00340 KMComposeWin *win; 00341 KMMessage *msg = new KMMessage; 00342 uint id = 0; 00343 00344 if ( mMessage && mMessage->parent() ) 00345 id = mMessage->parent()->identity(); 00346 00347 msg->initHeader(id); 00348 msg->setCharset("utf-8"); 00349 msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) ); 00350 00351 win = new KMComposeWin(msg, id); 00352 win->setCharset("", TRUE); 00353 win->setFocusToSubject(); 00354 win->show(); 00355 } 00356 00357 00358 KMMailtoReplyCommand::KMMailtoReplyCommand( QWidget *parent, 00359 const KURL &url, KMMessage *msg, const QString &selection ) 00360 :KMCommand( parent, msg ), mUrl( url ), mSelection( selection ) 00361 { 00362 } 00363 00364 void KMMailtoReplyCommand::execute() 00365 { 00366 //TODO : consider factoring createReply into this method. 00367 KMMessage *msg = retrievedMessage(); 00368 KMComposeWin *win; 00369 KMMessage *rmsg = msg->createReply( KMail::ReplyNone, mSelection ); 00370 rmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) ); 00371 00372 win = new KMComposeWin(rmsg, 0); 00373 win->setCharset(msg->codec()->mimeName(), TRUE); 00374 win->setReplyFocus(); 00375 win->show(); 00376 } 00377 00378 00379 KMMailtoForwardCommand::KMMailtoForwardCommand( QWidget *parent, 00380 const KURL &url, KMMessage *msg ) 00381 :KMCommand( parent, msg ), mUrl( url ) 00382 { 00383 } 00384 00385 void KMMailtoForwardCommand::execute() 00386 { 00387 //TODO : consider factoring createForward into this method. 00388 KMMessage *msg = retrievedMessage(); 00389 KMComposeWin *win; 00390 KMMessage *fmsg = msg->createForward(); 00391 fmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) ); 00392 00393 win = new KMComposeWin(fmsg); 00394 win->setCharset(msg->codec()->mimeName(), TRUE); 00395 win->show(); 00396 } 00397 00398 00399 KMAddBookmarksCommand::KMAddBookmarksCommand( const KURL &url, QWidget *parent ) 00400 :mUrl( url ), mParent( parent ) 00401 { 00402 } 00403 00404 void KMAddBookmarksCommand::execute() 00405 { 00406 QString filename = locateLocal( "data", QString::fromLatin1("konqueror/bookmarks.xml") ); 00407 KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename, 00408 false ); 00409 KBookmarkGroup group = bookManager->root(); 00410 group.addBookmark( bookManager, mUrl.path(), KURL( mUrl ) ); 00411 bookManager->save(); 00412 } 00413 00414 KMMailtoAddAddrBookCommand::KMMailtoAddAddrBookCommand( const KURL &url, 00415 QWidget *parent ) 00416 :mUrl( url ), mParent( parent ) 00417 { 00418 } 00419 00420 void KMMailtoAddAddrBookCommand::execute() 00421 { 00422 KMAddrBookExternal::addEmail( KMMessage::decodeMailtoUrl( mUrl.path() ), mParent ); 00423 } 00424 00425 00426 KMMailtoOpenAddrBookCommand::KMMailtoOpenAddrBookCommand( const KURL &url, 00427 QWidget *parent ) 00428 :mUrl( url ), mParent( parent ) 00429 { 00430 } 00431 00432 void KMMailtoOpenAddrBookCommand::execute() 00433 { 00434 KMAddrBookExternal::openEmail( KMMessage::decodeMailtoUrl( mUrl.path() ), mParent ); 00435 } 00436 00437 00438 KMUrlCopyCommand::KMUrlCopyCommand( const KURL &url, KMMainWidget *mainWidget ) 00439 :mUrl( url ), mMainWidget( mainWidget ) 00440 { 00441 } 00442 00443 void KMUrlCopyCommand::execute() 00444 { 00445 QClipboard* clip = QApplication::clipboard(); 00446 00447 if (mUrl.protocol() == "mailto") { 00448 // put the url into the mouse selection and the clipboard 00449 QString address = KMMessage::decodeMailtoUrl( mUrl.path() ); 00450 clip->setSelectionMode( true ); 00451 clip->setText( address ); 00452 clip->setSelectionMode( false ); 00453 clip->setText( address ); 00454 if (mMainWidget) 00455 mMainWidget->statusMsg( i18n( "Address copied to clipboard." )); 00456 } else { 00457 // put the url into the mouse selection and the clipboard 00458 clip->setSelectionMode( true ); 00459 clip->setText( mUrl.url() ); 00460 clip->setSelectionMode( false ); 00461 clip->setText( mUrl.url() ); 00462 if ( mMainWidget ) 00463 mMainWidget->statusMsg( i18n( "URL copied to clipboard." )); 00464 } 00465 } 00466 00467 00468 KMUrlOpenCommand::KMUrlOpenCommand( const KURL &url, KMReaderWin *readerWin ) 00469 :mUrl( url ), mReaderWin( readerWin ) 00470 { 00471 } 00472 00473 void KMUrlOpenCommand::execute() 00474 { 00475 if (mUrl.isEmpty()) return; 00476 mReaderWin->slotUrlOpen( mUrl, KParts::URLArgs() ); 00477 } 00478 00479 00480 KMUrlSaveCommand::KMUrlSaveCommand( const KURL &url, QWidget *parent ) 00481 :mUrl( url ), mParent( parent ) 00482 { 00483 } 00484 00485 void KMUrlSaveCommand::execute() 00486 { 00487 if (mUrl.isEmpty()) return; 00488 KURL saveUrl = KFileDialog::getSaveURL(mUrl.fileName(), QString::null, 00489 mParent); 00490 if (saveUrl.isEmpty()) return; 00491 if (KIO::NetAccess::exists(saveUrl, false, mParent)) 00492 { 00493 if (KMessageBox::warningContinueCancel(0, 00494 i18n("<qt>File <b>%1</b> exists.<br>Do you want to replace it?</qt>") 00495 .arg(saveUrl.prettyURL()), i18n("Save to File"), i18n("&Replace")) 00496 != KMessageBox::Continue) 00497 return; 00498 } 00499 KIO::Job *job = KIO::file_copy(mUrl, saveUrl, -1, true); 00500 connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotUrlSaveResult(KIO::Job*))); 00501 } 00502 00503 void KMUrlSaveCommand::slotUrlSaveResult( KIO::Job *job ) 00504 { 00505 if (job->error()) job->showErrorDialog(); 00506 } 00507 00508 00509 KMEditMsgCommand::KMEditMsgCommand( QWidget *parent, KMMessage *msg ) 00510 :KMCommand( parent, msg ) 00511 { 00512 } 00513 00514 void KMEditMsgCommand::execute() 00515 { 00516 KMMessage *msg = retrievedMessage(); 00517 if (!msg || !msg->parent() || 00518 !kmkernel->folderIsDraftOrOutbox( msg->parent() )) 00519 return; 00520 00521 // Remember the old parent, we need it a bit further down to be able 00522 // to put the unchanged messsage back in the drafts folder if the nth 00523 // edit is discarded, for n > 1. 00524 KMFolder *parent = msg->parent(); 00525 if ( parent ) 00526 parent->take( parent->find( msg ) ); 00527 #if 0 00528 // Useful? 00529 mHeaders->setSelected(mHeaders->currentItem(), TRUE); 00530 mHeaders->highlightMessage(mHeaders->currentItem(), true); 00531 #endif 00532 00533 KMComposeWin *win = new KMComposeWin(); 00534 #if 0 00535 // FIXME: Poor solution, won't work for multiple readerwins should use kmkernel as an observer 00536 QObject::connect( win, SIGNAL( messageQueuedOrDrafted()), 00537 this, SLOT( slotMessageQueuedOrDrafted()) ); 00538 #endif 00539 msg->setTransferInProgress(false); // From here on on, the composer owns the message. 00540 win->setMsg(msg, FALSE, TRUE); 00541 win->setFolder( parent ); 00542 win->show(); 00543 } 00544 00545 00546 KMShowMsgSrcCommand::KMShowMsgSrcCommand( QWidget *parent, 00547 KMMessage *msg, bool fixedFont ) 00548 :KMCommand( parent, msg ), mFixedFont( fixedFont ) 00549 { 00550 } 00551 00552 void KMShowMsgSrcCommand::execute() 00553 { 00554 KMMessage *msg = retrievedMessage(); 00555 QString str = QString::fromLatin1( msg->asString() ); 00556 00557 MailSourceViewer *viewer = new MailSourceViewer(); // deletes itself upon close 00558 viewer->setCaption( i18n("Message as Plain Text") ); 00559 viewer->setText(str); 00560 if( mFixedFont ) 00561 viewer->setFont(KGlobalSettings::fixedFont()); 00562 00563 // Well, there is no widget to be seen here, so we have to use QCursor::pos() 00564 // Update: (GS) I'm not going to make this code behave according to Xinerama 00565 // configuration because this is quite the hack. 00566 if (QApplication::desktop()->isVirtualDesktop()) { 00567 int scnum = QApplication::desktop()->screenNumber(QCursor::pos()); 00568 viewer->resize(QApplication::desktop()->screenGeometry(scnum).width()/2, 00569 2*QApplication::desktop()->screenGeometry(scnum).height()/3); 00570 } else { 00571 viewer->resize(QApplication::desktop()->geometry().width()/2, 00572 2*QApplication::desktop()->geometry().height()/3); 00573 } 00574 viewer->show(); 00575 } 00576 00577 namespace { 00578 KURL subjectToUrl( const QString & subject ) { 00579 return KFileDialog::getSaveURL( subject.mid( subject.findRev(':') + 1 ) 00580 .stripWhiteSpace() 00581 .replace( QDir::separator(), '_' ), 00582 QString::null ); 00583 } 00584 } 00585 00586 KMSaveMsgCommand::KMSaveMsgCommand( QWidget *parent, KMMessage * msg ) 00587 : KMCommand( parent ), 00588 mMsgListIndex( 0 ), 00589 mOffset( 0 ), 00590 mTotalSize( msg ? msg->msgSize() : 0 ) 00591 { 00592 if ( !msg ) return; 00593 setDeletesItself( true ); 00594 mMsgList.append( msg->getMsgSerNum() ); 00595 mUrl = subjectToUrl( msg->subject() ); 00596 } 00597 00598 KMSaveMsgCommand::KMSaveMsgCommand( QWidget *parent, 00599 const QPtrList<KMMsgBase> &msgList ) 00600 : KMCommand( parent ), 00601 mMsgListIndex( 0 ), 00602 mOffset( 0 ), 00603 mTotalSize( 0 ) 00604 { 00605 if (!msgList.getFirst()) 00606 return; 00607 setDeletesItself( true ); 00608 KMMsgBase *msgBase = msgList.getFirst(); 00609 00610 // We operate on serNums and not the KMMsgBase pointers, as those can 00611 // change, or become invalid when changing the current message, switching 00612 // folders, etc. 00613 QPtrListIterator<KMMsgBase> it(msgList); 00614 while ( it.current() ) { 00615 mMsgList.append( (*it)->getMsgSerNum() ); 00616 mTotalSize += (*it)->msgSize(); 00617 if ((*it)->parent() != 0) 00618 (*it)->parent()->open(); 00619 ++it; 00620 } 00621 mMsgListIndex = 0; 00622 mUrl = subjectToUrl( msgBase->subject() ); 00623 } 00624 00625 KURL KMSaveMsgCommand::url() 00626 { 00627 return mUrl; 00628 } 00629 00630 void KMSaveMsgCommand::execute() 00631 { 00632 mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, false, false ); 00633 mJob->slotTotalSize( mTotalSize ); 00634 mJob->setAsyncDataEnabled( true ); 00635 mJob->setReportDataSent( true ); 00636 connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)), 00637 SLOT(slotSaveDataReq())); 00638 connect(mJob, SIGNAL(result(KIO::Job*)), 00639 SLOT(slotSaveResult(KIO::Job*))); 00640 } 00641 00642 void KMSaveMsgCommand::slotSaveDataReq() 00643 { 00644 int remainingBytes = mData.size() - mOffset; 00645 if ( remainingBytes > 0 ) { 00646 // eat leftovers first 00647 if ( remainingBytes > MAX_CHUNK_SIZE ) 00648 remainingBytes = MAX_CHUNK_SIZE; 00649 00650 QByteArray data; 00651 data.duplicate( mData.data() + mOffset, remainingBytes ); 00652 mJob->sendAsyncData( data ); 00653 mOffset += remainingBytes; 00654 return; 00655 } 00656 // No leftovers, process next message. 00657 if ( mMsgListIndex < mMsgList.size() ) { 00658 KMMessage *msg = 0; 00659 int idx = -1; 00660 KMFolder * p = 0; 00661 kmkernel->msgDict()->getLocation( mMsgList[mMsgListIndex], &p, &idx ); 00662 assert( p ); 00663 assert( idx >= 0 ); 00664 msg = p->getMsg(idx); 00665 00666 if (msg->transferInProgress()) { 00667 QByteArray data = QByteArray(); 00668 mJob->sendAsyncData( data ); 00669 } 00670 msg->setTransferInProgress( true ); 00671 if (msg->isComplete() ) { 00672 slotMessageRetrievedForSaving(msg); 00673 } else { 00674 // retrieve Message first 00675 if (msg->parent() && !msg->isComplete() ) { 00676 FolderJob *job = msg->parent()->createJob(msg); 00677 connect(job, SIGNAL(messageRetrieved(KMMessage*)), 00678 this, SLOT(slotMessageRetrievedForSaving(KMMessage*))); 00679 job->start(); 00680 } 00681 } 00682 } else { 00683 // No more messages. Tell the putjob we are done. 00684 QByteArray data = QByteArray(); 00685 mJob->sendAsyncData( data ); 00686 } 00687 } 00688 00689 void KMSaveMsgCommand::slotMessageRetrievedForSaving(KMMessage *msg) 00690 { 00691 QCString str( msg->fromEmail() ); 00692 if ( str.isEmpty() ) 00693 str = "unknown@unknown.invalid"; 00694 str = "From " + str + " " + msg->dateShortStr() + "\n"; 00695 str += KMFolderMbox::escapeFrom( msg->asString() ); 00696 str += "\n"; 00697 msg->setTransferInProgress(false); 00698 00699 mData = str; 00700 mData.resize(mData.size() - 1); 00701 mOffset = 0; 00702 QByteArray data; 00703 int size; 00704 // Unless it is great than 64 k send the whole message. kio buffers for us. 00705 if( mData.size() > (unsigned int) MAX_CHUNK_SIZE ) 00706 size = MAX_CHUNK_SIZE; 00707 else 00708 size = mData.size(); 00709 00710 data.duplicate( mData, size ); 00711 mJob->sendAsyncData( data ); 00712 mOffset += size; 00713 ++mMsgListIndex; 00714 // Get rid of the message. 00715 if (msg->parent()) { 00716 int idx = -1; 00717 KMFolder * p = 0; 00718 kmkernel->msgDict()->getLocation( msg, &p, &idx ); 00719 assert( p == msg->parent() ); assert( idx >= 0 ); 00720 p->unGetMsg( idx ); 00721 p->close(); 00722 } 00723 } 00724 00725 void KMSaveMsgCommand::slotSaveResult(KIO::Job *job) 00726 { 00727 if (job->error()) 00728 { 00729 if (job->error() == KIO::ERR_FILE_ALREADY_EXIST) 00730 { 00731 if (KMessageBox::warningContinueCancel(0, 00732 i18n("File %1 exists.\nDo you want to replace it?") 00733 .arg(mUrl.prettyURL()), i18n("Save to File"), i18n("&Replace")) 00734 == KMessageBox::Continue) { 00735 mOffset = 0; 00736 00737 mJob = KIO::put( mUrl, S_IRUSR|S_IWUSR, true, false ); 00738 mJob->slotTotalSize( mTotalSize ); 00739 mJob->setAsyncDataEnabled( true ); 00740 mJob->setReportDataSent( true ); 00741 connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)), 00742 SLOT(slotSaveDataReq())); 00743 connect(mJob, SIGNAL(result(KIO::Job*)), 00744 SLOT(slotSaveResult(KIO::Job*))); 00745 } 00746 } 00747 else 00748 { 00749 job->showErrorDialog(); 00750 delete this; 00751 } 00752 } else { 00753 delete this; 00754 } 00755 } 00756 00757 //TODO: ReplyTo, NoQuoteReplyTo, ReplyList, ReplyToAll, ReplyAuthor 00758 // are all similar and should be factored 00759 KMReplyToCommand::KMReplyToCommand( QWidget *parent, KMMessage *msg, 00760 const QString &selection ) 00761 : KMCommand( parent, msg ), mSelection( selection ) 00762 { 00763 } 00764 00765 void KMReplyToCommand::execute() 00766 { 00767 KCursorSaver busy(KBusyPtr::busy()); 00768 KMMessage *msg = retrievedMessage(); 00769 KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection ); 00770 KMComposeWin *win = new KMComposeWin( reply ); 00771 win->setCharset( msg->codec()->mimeName(), TRUE ); 00772 win->setReplyFocus(); 00773 win->show(); 00774 } 00775 00776 00777 KMNoQuoteReplyToCommand::KMNoQuoteReplyToCommand( QWidget *parent, 00778 KMMessage *msg ) 00779 : KMCommand( parent, msg ) 00780 { 00781 } 00782 00783 void KMNoQuoteReplyToCommand::execute() 00784 { 00785 KCursorSaver busy(KBusyPtr::busy()); 00786 KMMessage *msg = retrievedMessage(); 00787 KMMessage *reply = msg->createReply( KMail::ReplySmart, "", TRUE); 00788 KMComposeWin *win = new KMComposeWin( reply ); 00789 win->setCharset(msg->codec()->mimeName(), TRUE); 00790 win->setReplyFocus(false); 00791 win->show(); 00792 } 00793 00794 00795 KMReplyListCommand::KMReplyListCommand( QWidget *parent, 00796 KMMessage *msg, const QString &selection ) 00797 : KMCommand( parent, msg ), mSelection( selection ) 00798 { 00799 } 00800 00801 void KMReplyListCommand::execute() 00802 { 00803 KCursorSaver busy(KBusyPtr::busy()); 00804 KMMessage *msg = retrievedMessage(); 00805 KMMessage *reply = msg->createReply( KMail::ReplyList, mSelection); 00806 KMComposeWin *win = new KMComposeWin( reply ); 00807 win->setCharset(msg->codec()->mimeName(), TRUE); 00808 win->setReplyFocus(false); 00809 win->show(); 00810 } 00811 00812 00813 KMReplyToAllCommand::KMReplyToAllCommand( QWidget *parent, 00814 KMMessage *msg, const QString &selection ) 00815 :KMCommand( parent, msg ), mSelection( selection ) 00816 { 00817 } 00818 00819 void KMReplyToAllCommand::execute() 00820 { 00821 KCursorSaver busy(KBusyPtr::busy()); 00822 KMMessage *msg = retrievedMessage(); 00823 KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection ); 00824 KMComposeWin *win = new KMComposeWin( reply ); 00825 win->setCharset( msg->codec()->mimeName(), TRUE ); 00826 win->setReplyFocus(); 00827 win->show(); 00828 } 00829 00830 00831 KMReplyAuthorCommand::KMReplyAuthorCommand( QWidget *parent, KMMessage *msg, 00832 const QString &selection ) 00833 : KMCommand( parent, msg ), mSelection( selection ) 00834 { 00835 } 00836 00837 void KMReplyAuthorCommand::execute() 00838 { 00839 KCursorSaver busy(KBusyPtr::busy()); 00840 KMMessage *msg = retrievedMessage(); 00841 KMMessage *reply = msg->createReply( KMail::ReplyAuthor, mSelection ); 00842 KMComposeWin *win = new KMComposeWin( reply ); 00843 win->setCharset( msg->codec()->mimeName(), TRUE ); 00844 win->setReplyFocus(); 00845 win->show(); 00846 } 00847 00848 00849 KMForwardCommand::KMForwardCommand( QWidget *parent, 00850 const QPtrList<KMMsgBase> &msgList, uint identity ) 00851 : KMCommand( parent, msgList ), 00852 mParent( parent ), 00853 mIdentity( identity ) 00854 { 00855 } 00856 00857 KMForwardCommand::KMForwardCommand( QWidget *parent, KMMessage *msg, 00858 uint identity ) 00859 : KMCommand( parent, msg ), 00860 mParent( parent ), 00861 mIdentity( identity ) 00862 { 00863 } 00864 00865 void KMForwardCommand::execute() 00866 { 00867 KMComposeWin *win; 00868 QPtrList<KMMessage> msgList = retrievedMsgs(); 00869 00870 if (msgList.count() >= 2) { 00871 // ask if they want a mime digest forward 00872 00873 if (KMessageBox::questionYesNo(mParent, i18n("Forward selected messages as" 00874 " a MIME digest?")) 00875 == KMessageBox::Yes) { 00876 uint id = 0; 00877 KMMessage *fwdMsg = new KMMessage; 00878 KMMessagePart *msgPart = new KMMessagePart; 00879 QString msgPartText; 00880 int msgCnt = 0; // incase there are some we can't forward for some reason 00881 00882 // dummy header initialization; initialization with the correct identity 00883 // is done below 00884 fwdMsg->initHeader(id); 00885 fwdMsg->setAutomaticFields(true); 00886 fwdMsg->mMsg->Headers().ContentType().CreateBoundary(1); 00887 QCString boundary( fwdMsg->mMsg->Headers().ContentType().Boundary().c_str() ); 00888 msgPartText = i18n("\nThis is a MIME digest forward. The content of the" 00889 " message is contained in the attachment(s).\n\n\n"); 00890 // iterate through all the messages to be forwarded 00891 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) { 00892 // set the identity 00893 if (id == 0) 00894 id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt(); 00895 // set the part header 00896 msgPartText += "--"; 00897 msgPartText += QString::fromLatin1( boundary ); 00898 msgPartText += "\nContent-Type: MESSAGE/RFC822"; 00899 msgPartText += QString("; CHARSET=%1").arg(msg->charset()); 00900 msgPartText += "\n"; 00901 DwHeaders dwh; 00902 dwh.MessageId().CreateDefault(); 00903 msgPartText += QString("Content-ID: %1\n").arg(dwh.MessageId().AsString().c_str()); 00904 msgPartText += QString("Content-Description: %1").arg(msg->subject()); 00905 if (!msg->subject().contains("(fwd)")) 00906 msgPartText += " (fwd)"; 00907 msgPartText += "\n\n"; 00908 // remove headers that shouldn't be forwarded 00909 msg->removePrivateHeaderFields(); 00910 msg->removeHeaderField("BCC"); 00911 // set the part 00912 msgPartText += msg->headerAsString(); 00913 msgPartText += "\n"; 00914 msgPartText += msg->body(); 00915 msgPartText += "\n"; // eot 00916 msgCnt++; 00917 fwdMsg->link(msg, KMMsgStatusForwarded); 00918 } 00919 if ( id == 0 ) 00920 id = mIdentity; // use folder identity if no message had an id set 00921 fwdMsg->initHeader(id); 00922 msgPartText += "--"; 00923 msgPartText += QString::fromLatin1( boundary ); 00924 msgPartText += "--\n"; 00925 QCString tmp; 00926 msgPart->setTypeStr("MULTIPART"); 00927 tmp.sprintf( "Digest; boundary=\"%s\"", boundary.data() ); 00928 msgPart->setSubtypeStr( tmp ); 00929 msgPart->setName("unnamed"); 00930 msgPart->setCte(DwMime::kCte7bit); // does it have to be 7bit? 00931 msgPart->setContentDescription(QString("Digest of %1 messages.").arg(msgCnt)); 00932 // THIS HAS TO BE AFTER setCte()!!!! 00933 msgPart->setBodyEncoded(QCString(msgPartText.ascii())); 00934 KCursorSaver busy(KBusyPtr::busy()); 00935 win = new KMComposeWin(fwdMsg, id); 00936 win->addAttach(msgPart); 00937 win->show(); 00938 return; 00939 } else { // NO MIME DIGEST, Multiple forward 00940 uint id = 0; 00941 QCString msgText = ""; 00942 QPtrList<KMMessage> linklist; 00943 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) { 00944 // set the identity 00945 if (id == 0) 00946 id = msg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt(); 00947 00948 msgText += msg->createForwardBody(); 00949 linklist.append(msg); 00950 } 00951 if ( id == 0 ) 00952 id = mIdentity; // use folder identity if no message had an id set 00953 KMMessage *fwdMsg = new KMMessage; 00954 fwdMsg->initHeader(id); 00955 fwdMsg->setAutomaticFields(true); 00956 fwdMsg->setCharset("utf-8"); 00957 fwdMsg->setBody(msgText); 00958 00959 for (KMMessage *msg = linklist.first(); msg; msg = linklist.next()) 00960 fwdMsg->link(msg, KMMsgStatusForwarded); 00961 00962 KCursorSaver busy(KBusyPtr::busy()); 00963 win = new KMComposeWin(fwdMsg, id); 00964 win->setCharset(""); 00965 win->show(); 00966 return; 00967 } 00968 } 00969 00970 // forward a single message at most. 00971 00972 KMMessage *msg = msgList.getFirst(); 00973 if (!msg || !msg->codec()) return; 00974 00975 KCursorSaver busy(KBusyPtr::busy()); 00976 win = new KMComposeWin(msg->createForward()); 00977 win->setCharset(msg->codec()->mimeName(), TRUE); 00978 win->show(); 00979 } 00980 00981 00982 KMForwardAttachedCommand::KMForwardAttachedCommand( QWidget *parent, 00983 const QPtrList<KMMsgBase> &msgList, uint identity, KMComposeWin *win ) 00984 : KMCommand( parent, msgList ), mIdentity( identity ), 00985 mWin( QGuardedPtr< KMComposeWin >( win )) 00986 { 00987 } 00988 00989 KMForwardAttachedCommand::KMForwardAttachedCommand( QWidget *parent, 00990 KMMessage * msg, uint identity, KMComposeWin *win ) 00991 : KMCommand( parent, msg ), mIdentity( identity ), 00992 mWin( QGuardedPtr< KMComposeWin >( win )) 00993 { 00994 } 00995 00996 void KMForwardAttachedCommand::execute() 00997 { 00998 QPtrList<KMMessage> msgList = retrievedMsgs(); 00999 KMMessage *fwdMsg = new KMMessage; 01000 01001 if (msgList.count() >= 2) { 01002 // don't respect X-KMail-Identity headers because they might differ for 01003 // the selected mails 01004 fwdMsg->initHeader(mIdentity); 01005 } 01006 else if (msgList.count() == 1) { 01007 KMMessage *msg = msgList.getFirst(); 01008 fwdMsg->initFromMessage(msg); 01009 fwdMsg->setSubject( msg->forwardSubject() ); 01010 } 01011 01012 fwdMsg->setAutomaticFields(true); 01013 01014 KCursorSaver busy(KBusyPtr::busy()); 01015 if (!mWin) 01016 mWin = new KMComposeWin(fwdMsg, mIdentity); 01017 01018 // iterate through all the messages to be forwarded 01019 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) { 01020 // remove headers that shouldn't be forwarded 01021 msg->removePrivateHeaderFields(); 01022 msg->removeHeaderField("BCC"); 01023 // set the part 01024 KMMessagePart *msgPart = new KMMessagePart; 01025 msgPart->setTypeStr("message"); 01026 msgPart->setSubtypeStr("rfc822"); 01027 msgPart->setCharset(msg->charset()); 01028 msgPart->setName("forwarded message"); 01029 msgPart->setContentDescription(msg->from()+": "+msg->subject()); 01030 msgPart->setContentDisposition( "inline" ); 01031 // THIS HAS TO BE AFTER setCte()!!!! 01032 QValueList<int> dummy; 01033 msgPart->setBodyAndGuessCte(msg->asString(), dummy, true); 01034 msgPart->setCharset(""); 01035 01036 fwdMsg->link(msg, KMMsgStatusForwarded); 01037 mWin->addAttach(msgPart); 01038 } 01039 01040 mWin->show(); 01041 } 01042 01043 01044 KMRedirectCommand::KMRedirectCommand( QWidget *parent, 01045 KMMessage *msg ) 01046 : KMCommand( parent, msg ) 01047 { 01048 } 01049 01050 void KMRedirectCommand::execute() 01051 { 01052 //TODO: move KMMessage::createRedirect to here 01053 KMComposeWin *win; 01054 KMMessage *msg = retrievedMessage(); 01055 if (!msg || !msg->codec()) return; 01056 01057 KCursorSaver busy(KBusyPtr::busy()); 01058 win = new KMComposeWin(); 01059 win->setMsg(msg->createRedirect(), FALSE); 01060 win->setCharset(msg->codec()->mimeName()); 01061 win->show(); 01062 } 01063 01064 01065 KMBounceCommand::KMBounceCommand( QWidget *parent, 01066 KMMessage *msg ) 01067 : KMCommand( parent, msg ) 01068 { 01069 } 01070 01071 void KMBounceCommand::execute() 01072 { 01073 KMMessage *msg = retrievedMessage(); 01074 KMMessage *newMsg = msg->createBounce( TRUE /* with UI */); 01075 if (newMsg) 01076 kmkernel->msgSender()->send(newMsg, kmkernel->msgSender()->sendImmediate()); 01077 } 01078 01079 01080 KMPrintCommand::KMPrintCommand( QWidget *parent, 01081 KMMessage *msg, bool htmlOverride ) 01082 : KMCommand( parent, msg ), mHtmlOverride( htmlOverride ) 01083 { 01084 } 01085 01086 void KMPrintCommand::execute() 01087 { 01088 KMReaderWin printWin( 0, 0, 0 ); 01089 printWin.setPrinting(TRUE); 01090 printWin.readConfig(); 01091 printWin.setHtmlOverride( mHtmlOverride ); 01092 printWin.setMsg(retrievedMessage(), TRUE); 01093 printWin.printMsg(); 01094 } 01095 01096 01097 KMSetStatusCommand::KMSetStatusCommand( KMMsgStatus status, 01098 const QValueList<Q_UINT32> &serNums, bool toggle ) 01099 : mStatus( status ), mSerNums( serNums ), mToggle( toggle ) 01100 { 01101 } 01102 01103 void KMSetStatusCommand::execute() 01104 { 01105 QValueListIterator<Q_UINT32> it; 01106 int idx = -1; 01107 KMFolder *folder = 0; 01108 bool parentStatus = false; 01109 01110 // Toggle actions on threads toggle the whole thread 01111 // depending on the state of the parent. 01112 if (mToggle) { 01113 KMMsgBase *msg; 01114 kmkernel->msgDict()->getLocation( *mSerNums.begin(), &folder, &idx ); 01115 if (folder) { 01116 msg = folder->getMsgBase(idx); 01117 if (msg && (msg->status()&mStatus)) 01118 parentStatus = true; 01119 else 01120 parentStatus = false; 01121 } 01122 } 01123 QMap< KMFolder*, QValueList<int> > folderMap; 01124 for ( it = mSerNums.begin(); it != mSerNums.end(); ++it ) { 01125 kmkernel->msgDict()->getLocation( *it, &folder, &idx ); 01126 if (folder) { 01127 if (mToggle) { 01128 KMMsgBase *msg = folder->getMsgBase(idx); 01129 // check if we are already at the target toggle state 01130 if (msg) { 01131 bool myStatus; 01132 if (msg->status()&mStatus) 01133 myStatus = true; 01134 else 01135 myStatus = false; 01136 if (myStatus != parentStatus) 01137 continue; 01138 } 01139 } 01140 /* Collect the ids for each folder in a separate list and 01141 send them off in one go at the end. */ 01142 folderMap[folder].append(idx); 01143 } 01144 } 01145 QMapIterator< KMFolder*, QValueList<int> > it2 = folderMap.begin(); 01146 while ( it2 != folderMap.end() ) { 01147 KMFolder *f = it2.key(); 01148 f->setStatus( (*it2), mStatus, mToggle ); 01149 ++it2; 01150 } 01151 } 01152 01153 01154 KMFilterCommand::KMFilterCommand( const QCString &field, const QString &value ) 01155 : mField( field ), mValue( value ) 01156 { 01157 } 01158 01159 void KMFilterCommand::execute() 01160 { 01161 kmkernel->filterMgr()->createFilter( mField, mValue ); 01162 } 01163 01164 01165 KMMailingListFilterCommand::KMMailingListFilterCommand( QWidget *parent, 01166 KMMessage *msg ) 01167 : KMCommand( parent, msg ) 01168 { 01169 } 01170 01171 KMFilterActionCommand::KMFilterActionCommand( QWidget *parent, 01172 const QPtrList<KMMsgBase> &msgList, 01173 KMFilter *filter ) 01174 : KMCommand( parent, msgList ), mFilter( filter ) 01175 { 01176 } 01177 01178 void KMFilterActionCommand::execute() 01179 { 01180 QPtrList<KMMessage> msgList = retrievedMsgs(); 01181 01182 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) 01183 kmkernel->filterMgr()->tempOpenFolder(msg->parent()); 01184 01185 for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) { 01186 msg->setTransferInProgress(false); 01187 01188 int filterResult = kmkernel->filterMgr()->process(msg, mFilter); 01189 if (filterResult == 2) { 01190 // something went horribly wrong (out of space?) 01191 perror("Critical error"); 01192 kmkernel->emergencyExit( i18n("Not enough free disk space?" )); 01193 } 01194 msg->setTransferInProgress(true); 01195 } 01196 } 01197 01198 01199 KMMetaFilterActionCommand::KMMetaFilterActionCommand( KMFilter *filter, 01200 KMHeaders *headers, 01201 KMMainWidget *main ) 01202 : QObject( main ), 01203 mFilter( filter ), mHeaders( headers ), mMainWidget( main ) 01204 { 01205 } 01206 01207 void KMMetaFilterActionCommand::start() 01208 { 01209 #if 0 // use action scheduler 01210 KMFilterMgr::FilterSet set = KMFilterMgr::All; 01211 QPtrList<KMFilter> filters; 01212 filters.append( mFilter ); 01213 ActionScheduler *scheduler = new ActionScheduler( set, filters, mHeaders ); 01214 scheduler->setAlwaysMatch( true ); 01215 scheduler->setAutoDestruct( true ); 01216 01217 int contentX, contentY; 01218 KMHeaderItem *nextItem = mHeaders->prepareMove( &contentX, &contentY ); 01219 QPtrList<KMMsgBase> msgList = *mHeaders->selectedMsgs(true); 01220 mHeaders->finalizeMove( nextItem, contentX, contentY ); 01221 01222 01223 for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next()) 01224 scheduler->execFilters( msg ); 01225 #else 01226 KMCommand *filterCommand = new KMFilterActionCommand( mMainWidget, 01227 *mHeaders->selectedMsgs(), mFilter); 01228 filterCommand->start(); 01229 #endif 01230 } 01231 01232 01233 void KMMailingListFilterCommand::execute() 01234 { 01235 QCString name; 01236 QString value; 01237 KMMessage *msg = retrievedMessage(); 01238 if (!msg) 01239 return; 01240 01241 if (!KMMLInfo::name( msg, name, value ).isNull()) 01242 kmkernel->filterMgr()->createFilter( name, value ); 01243 } 01244 01245 01246 QPopupMenu* KMMenuCommand::folderToPopupMenu(bool move, 01247 QObject *receiver, KMMenuToFolder *aMenuToFolder, QPopupMenu *menu ) 01248 { 01249 while ( menu->count() ) 01250 { 01251 QPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup(); 01252 if (popup) 01253 delete popup; 01254 else 01255 menu->removeItemAt( 0 ); 01256 } 01257 01258 if (!kmkernel->imapFolderMgr()->dir().first()) { 01259 KMMenuCommand::makeFolderMenu( &kmkernel->folderMgr()->dir(), move, 01260 receiver, aMenuToFolder, menu ); 01261 } else { 01262 // operate on top-level items 01263 QPopupMenu* subMenu = new QPopupMenu(menu); 01264 subMenu = KMMenuCommand::makeFolderMenu( &kmkernel->folderMgr()->dir(), 01265 move, receiver, aMenuToFolder, subMenu ); 01266 menu->insertItem( i18n( "Local Folders" ), subMenu ); 01267 KMFolderDir* fdir = &kmkernel->imapFolderMgr()->dir(); 01268 for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) { 01269 if (node->isDir()) 01270 continue; 01271 subMenu = new QPopupMenu(menu); 01272 subMenu = makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu ); 01273 menu->insertItem( node->label(), subMenu ); 01274 } 01275 } 01276 01277 return menu; 01278 } 01279 01280 QPopupMenu* KMMenuCommand::makeFolderMenu(KMFolderNode* node, bool move, 01281 QObject *receiver, KMMenuToFolder *aMenuToFolder, QPopupMenu *menu ) 01282 { 01283 // connect the signals 01284 if (move) 01285 { 01286 disconnect(menu, SIGNAL(activated(int)), receiver, 01287 SLOT(moveSelectedToFolder(int))); 01288 connect(menu, SIGNAL(activated(int)), receiver, 01289 SLOT(moveSelectedToFolder(int))); 01290 } else { 01291 disconnect(menu, SIGNAL(activated(int)), receiver, 01292 SLOT(copySelectedToFolder(int))); 01293 connect(menu, SIGNAL(activated(int)), receiver, 01294 SLOT(copySelectedToFolder(int))); 01295 } 01296 01297 KMFolder *folder = 0; 01298 KMFolderDir *folderDir = 0; 01299 if (node->isDir()) { 01300 folderDir = static_cast<KMFolderDir*>(node); 01301 } else { 01302 folder = static_cast<KMFolder*>(node); 01303 folderDir = folder->child(); 01304 } 01305 01306 if (folder && !folder->noContent()) 01307 { 01308 int menuId; 01309 if (move) 01310 menuId = menu->insertItem(i18n("Move to This Folder")); 01311 else 01312 menuId = menu->insertItem(i18n("Copy to This Folder")); 01313 aMenuToFolder->insert( menuId, folder ); 01314 menu->insertSeparator(); 01315 } 01316 01317 if (!folderDir) 01318 return menu; 01319 01320 for (KMFolderNode *it = folderDir->first(); it; it = folderDir->next() ) { 01321 if (it->isDir()) 01322 continue; 01323 KMFolder *child = static_cast<KMFolder*>(it); 01324 QString label = child->label(); 01325 label.replace("&","&&"); 01326 if (child->child() && child->child()->first()) { 01327 // descend 01328 QPopupMenu *subMenu = makeFolderMenu(child, move, receiver, 01329 aMenuToFolder, new QPopupMenu(menu, "subMenu")); 01330 menu->insertItem(label, subMenu); 01331 } else { 01332 // insert an item 01333 int menuId = menu->insertItem(label); 01334 aMenuToFolder->insert( menuId, child ); 01335 } 01336 } 01337 return menu; 01338 } 01339 01340 01341 KMCopyCommand::KMCopyCommand( KMFolder* destFolder, 01342 const QPtrList<KMMsgBase> &msgList ) 01343 :mDestFolder( destFolder ), mMsgList( msgList ) 01344 { 01345 } 01346 01347 KMCopyCommand::KMCopyCommand( KMFolder* destFolder, KMMessage * msg ) 01348 :mDestFolder( destFolder ) 01349 { 01350 mMsgList.append( &msg->toMsgBase() ); 01351 } 01352 01353 void KMCopyCommand::execute() 01354 { 01355 KMMsgBase *msgBase; 01356 KMMessage *msg, *newMsg; 01357 int idx = -1; 01358 bool isMessage; 01359 QPtrList<KMMessage> list; 01360 01361 KCursorSaver busy(KBusyPtr::busy()); 01362 01363 for (msgBase = mMsgList.first(); msgBase; msgBase = mMsgList.next() ) 01364 { 01365 KMFolder *srcFolder = msgBase->parent(); 01366 if (isMessage = msgBase->isMessage()) 01367 { 01368 msg = static_cast<KMMessage*>(msgBase); 01369 } else { 01370 idx = srcFolder->find(msgBase); 01371 assert(idx != -1); 01372 msg = srcFolder->getMsg(idx); 01373 } 01374 01375 if (srcFolder && 01376 (srcFolder->folderType()== KMFolderTypeImap) && 01377 (mDestFolder->folderType() == KMFolderTypeImap) && 01378 (static_cast<KMFolderImap*>(srcFolder)->account() == 01379 static_cast<KMFolderImap*>(mDestFolder)->account())) 01380 { 01381 list.append(msg); 01382 } else { 01383 newMsg = new KMMessage; 01384 newMsg->fromString(msg->asString()); 01385 newMsg->setStatus(msg->status()); 01386 newMsg->setComplete(msg->isComplete()); 01387 01388 if (srcFolder && !newMsg->isComplete()) 01389 { 01390 newMsg->setParent(msg->parent()); 01391 FolderJob *job = srcFolder->createJob(newMsg); 01392 connect(job, SIGNAL(messageRetrieved(KMMessage*)), 01393 mDestFolder, SLOT(reallyAddCopyOfMsg(KMMessage*))); 01394 // msg musn't be deleted 01395 newMsg->setTransferInProgress(true); 01396 job->start(); 01397 } else { 01398 int rc, index; 01399 rc = mDestFolder->addMsg(newMsg, &index); 01400 if (rc == 0 && index != -1) 01401 mDestFolder->unGetMsg( mDestFolder->count() - 1 ); 01402 } 01403 } 01404 01405 if (!isMessage && list.isEmpty()) 01406 { 01407 assert(idx != -1); 01408 srcFolder->unGetMsg( idx ); 01409 } 01410 01411 } // end for 01412 01413 //TODO: Get rid of the other cases just use this one for all types of folder 01414 //TODO: requires adding copyMsg and getFolder methods to KMFolder.h 01415 01416 if (!list.isEmpty()) 01417 { 01418 // copy the message(s); note: the list is empty afterwards! 01419 KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder); 01420 imapDestFolder->copyMsg(list); 01421 imapDestFolder->getFolder(); 01422 } 01423 01424 } 01425 01426 01427 KMMoveCommand::KMMoveCommand( KMFolder* destFolder, 01428 const QPtrList<KMMsgBase> &msgList) 01429 :mDestFolder( destFolder ), mMsgList( msgList ) 01430 { 01431 setDeletesItself( true ); 01432 } 01433 01434 KMMoveCommand::KMMoveCommand( KMFolder* destFolder, 01435 KMMessage *msg ) 01436 :mDestFolder( destFolder ) 01437 { 01438 setDeletesItself( true ); 01439 mMsgList.append( &msg->toMsgBase() ); 01440 } 01441 01442 KMMoveCommand::KMMoveCommand( KMFolder* destFolder, 01443 KMMsgBase *msgBase ) 01444 :mDestFolder( destFolder ) 01445 { 01446 setDeletesItself( true ); 01447 mMsgList.append( msgBase ); 01448 } 01449 01450 void KMMoveCommand::execute() 01451 { 01452 typedef QMap< KMFolder*, QPtrList<KMMessage>* > FolderToMessageListMap; 01453 FolderToMessageListMap folderDeleteList; 01454 01455 if (mDestFolder && mDestFolder->open() != 0) 01456 return; 01457 KCursorSaver busy(KBusyPtr::busy()); 01458 01459 KMMessage *msg; 01460 KMMsgBase *msgBase; 01461 int rc = 0; 01462 int index; 01463 QPtrList<KMMessage> list; 01464 int undoId = -1; 01465 01466 if (mDestFolder) { 01467 connect (mDestFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)), 01468 this, SLOT(slotMsgAddedToDestFolder(KMFolder*, Q_UINT32))); 01469 01470 } 01471 01472 for (msgBase=mMsgList.first(); msgBase && !rc; msgBase=mMsgList.next()) { 01473 KMFolder *srcFolder = msgBase->parent(); 01474 if (srcFolder == mDestFolder) 01475 continue; 01476 bool undo = msgBase->enableUndo(); 01477 int idx = srcFolder->find(msgBase); 01478 assert(idx != -1); 01479 if ( msgBase->isMessage() ) 01480 msg = static_cast<KMMessage*>(msgBase); 01481 else 01482 msg = srcFolder->getMsg(idx); 01483 01484 if ( msg->transferInProgress() && 01485 srcFolder->folderType() == KMFolderTypeImap ) 01486 { 01487 // cancel the download 01488 msg->setTransferInProgress( false, true ); 01489 static_cast<KMFolderImap*>(srcFolder)->ignoreJobsForMessage( msg ); 01490 } 01491 01492 if (mDestFolder) { 01493 mLostBoys.append(msg->getMsgSerNum()); 01494 if (mDestFolder->folderType() == KMFolderTypeImap) { 01495 /* If we are moving to an imap folder, connect to it's completed 01496 * siganl so we notice when all the mails should have showed up in it 01497 * but haven't for some reason. */ 01498 connect (mDestFolder, SIGNAL(folderComplete( KMFolderImap*, bool )), 01499 this, SLOT(slotImapFolderCompleted( KMFolderImap*, bool ))); 01500 list.append(msg); 01501 } else { 01502 // We are moving to a local folder. 01503 rc = mDestFolder->moveMsg(msg, &index); 01504 if (rc == 0 && index != -1) { 01505 KMMsgBase *mb = mDestFolder->unGetMsg( mDestFolder->count() - 1 ); 01506 if (undo && mb) 01507 { 01508 if ( undoId == -1 ) 01509 undoId = kmkernel->undoStack()->newUndoAction( srcFolder, mDestFolder ); 01510 kmkernel->undoStack()->addMsgToAction( undoId, mb->getMsgSerNum() ); 01511 } 01512 } else if (rc != 0) { 01513 // Something went wrong. Stop processing here, it is likely that the 01514 // other moves would fail as well. 01515 emit completed( false); 01516 deleteLater(); 01517 return; 01518 } 01519 } 01520 } else { 01521 // really delete messages that are already in the trash folder or if 01522 // we are really, really deleting, not just moving to trash 01523 if (srcFolder->folderType() == KMFolderTypeImap) { 01524 if (!folderDeleteList[srcFolder]) 01525 folderDeleteList[srcFolder] = new QPtrList<KMMessage>; 01526 folderDeleteList[srcFolder]->append( msg ); 01527 } else { 01528 srcFolder->removeMsg(idx); 01529 delete msg; 01530 } 01531 } 01532 } 01533 if (!list.isEmpty() && mDestFolder) { 01534 mDestFolder->moveMsg(list, &index); 01535 } else { 01536 FolderToMessageListMap::Iterator it; 01537 for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) { 01538 it.key()->removeMsg(*it.data()); 01539 delete it.data(); 01540 } 01541 /* The list is empty, which means that either all messages were to be 01542 * deleted, which is done above, or all of them were already in this folder. 01543 * In both cases make sure a completed() signal is emitted nonetheless. */ 01544 KMFolder *srcFolder = 0; 01545 if ( mMsgList.first() ) { 01546 srcFolder = mMsgList.first()->parent(); 01547 if ( mDestFolder && mDestFolder == srcFolder ) { 01548 emit completed( true ); 01549 deleteLater(); 01550 } 01551 } 01552 if ( !mDestFolder ) { 01553 emit completed( true ); 01554 deleteLater(); 01555 } 01556 } 01557 } 01558 01559 void KMMoveCommand::slotImapFolderCompleted(KMFolderImap *, bool success) 01560 { 01561 if ( success ) { 01562 // the folder was checked successfully but we were still called, so check 01563 // if we are still waiting for messages to show up. If so, uidValidity 01564 // changed, or something else went wrong. Clean up. 01565 01566 /* Unfortunately older UW imap servers change uid validity for each put job. 01567 * Yes, it is really that broken. *sigh* So we cannot report error here, I guess. */ 01568 if ( !mLostBoys.isEmpty() ) { 01569 kdDebug(5006) << "### Not all moved messages reported back that they were " << endl 01570 << "### added to the target folder. Did uidValidity change? " << endl; 01571 } 01572 } else { 01573 // Should we inform the user here or leave that to the caller? 01574 } 01575 emit completed( success ); 01576 deleteLater(); 01577 } 01578 01579 void KMMoveCommand::slotMsgAddedToDestFolder(KMFolder *folder, Q_UINT32 serNum) 01580 { 01581 if (folder != mDestFolder) { 01582 kdDebug(5006) << "KMMoveCommand::msgAddedToDestFolder different " 01583 "folder or invalid serial number." << endl; 01584 return; 01585 } 01586 mLostBoys.remove(serNum); 01587 if ( mLostBoys.isEmpty() ) { 01588 // we are done. All messages transferred to the host succesfully 01589 if (mDestFolder && mDestFolder->folderType() != KMFolderTypeImap) { 01590 mDestFolder->sync(); 01591 } 01592 emit completed( true ); 01593 deleteLater(); 01594 } 01595 } 01596 01597 // srcFolder doesn't make much sense for searchFolders 01598 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, 01599 const QPtrList<KMMsgBase> &msgList ) 01600 :KMMoveCommand(findTrashFolder( srcFolder ), msgList) 01601 { 01602 } 01603 01604 KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg ) 01605 :KMMoveCommand(findTrashFolder( srcFolder ), msg) 01606 { 01607 } 01608 01609 01610 KMFolder * KMDeleteMsgCommand::findTrashFolder( KMFolder * folder ) 01611 { 01612 if (folder->folderType()== KMFolderTypeImap) 01613 { 01614 KMFolderImap* fi = static_cast<KMFolderImap*> (folder); 01615 QString trashStr = fi->account()->trash(); 01616 KMFolder* trash = kmkernel->imapFolderMgr()->findIdString( trashStr ); 01617 if (!trash) trash = kmkernel->trashFolder(); 01618 if (folder != trash) 01619 return trash; 01620 } else { 01621 if (folder != kmkernel->trashFolder()) 01622 // move to trash folder 01623 return kmkernel->trashFolder(); 01624 } 01625 return 0; 01626 } 01627 01628 KMUrlClickedCommand::KMUrlClickedCommand( const KURL &url, uint identity, 01629 KMReaderWin *readerWin, bool htmlPref, KMMainWidget *mainWidget ) 01630 :mUrl( url ), mIdentity( identity ), mReaderWin( readerWin ), 01631 mHtmlPref( htmlPref ), mMainWidget( mainWidget ) 01632 { 01633 } 01634 01635 void KMUrlClickedCommand::execute() 01636 { 01637 KMComposeWin *win; 01638 KMMessage* msg; 01639 01640 if (mUrl.protocol() == "mailto") 01641 { 01642 msg = new KMMessage; 01643 msg->initHeader(mIdentity); 01644 msg->setCharset("utf-8"); 01645 msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) ); 01646 QString query=mUrl.query(); 01647 while (!query.isEmpty()) { 01648 QString queryPart; 01649 int secondQuery = query.find('?',1); 01650 if (secondQuery != -1) 01651 queryPart = query.left(secondQuery); 01652 else 01653 queryPart = query; 01654 query = query.mid(queryPart.length()); 01655 01656 if (queryPart.left(9) == "?subject=") 01657 msg->setSubject( KURL::decode_string(queryPart.mid(9)) ); 01658 else if (queryPart.left(6) == "?body=") 01659 // It is correct to convert to latin1() as URL should not contain 01660 // anything except ascii. 01661 msg->setBody( KURL::decode_string(queryPart.mid(6)).latin1() ); 01662 else if (queryPart.left(4) == "?cc=") 01663 msg->setCc( KURL::decode_string(queryPart.mid(4)) ); 01664 } 01665 01666 win = new KMComposeWin(msg, mIdentity); 01667 win->setCharset("", TRUE); 01668 win->show(); 01669 } 01670 else if ((mUrl.protocol() == "http") || (mUrl.protocol() == "https") || 01671 (mUrl.protocol() == "ftp") || (mUrl.protocol() == "file") || 01672 (mUrl.protocol() == "ftps") || (mUrl.protocol() == "sftp" ) || 01673 (mUrl.protocol() == "help") || (mUrl.protocol() == "vnc") || 01674 (mUrl.protocol() == "smb")) 01675 { 01676 if (mMainWidget) 01677 mMainWidget->statusMsg( i18n("Opening URL...")); 01678 KMimeType::Ptr mime = KMimeType::findByURL( mUrl ); 01679 if (mime->name() == "application/x-desktop" || 01680 mime->name() == "application/x-executable" || 01681 mime->name() == "application/x-msdos-program" || 01682 mime->name() == "application/x-shellscript" ) 01683 { 01684 if (KMessageBox::warningYesNo( 0, i18n( "<qt>Do you really want to execute <b>%1</b>?</qt>" ) 01685 .arg( mUrl.prettyURL() ) ) != KMessageBox::Yes) return; 01686 } 01687 (void) new KRun( mUrl ); 01688 } 01689 } 01690 01691 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, KMMessage *msg ) 01692 : KMCommand( parent, msg ), mParent( parent ), mEncoded( false ) 01693 { 01694 } 01695 01696 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, const QPtrList<KMMsgBase>& msgs ) 01697 : KMCommand( parent, msgs ), mParent( parent ), mEncoded( false ) 01698 { 01699 } 01700 01701 KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( QWidget *parent, QPtrList<partNode>& attachments, 01702 KMMessage *msg, bool encoded ) 01703 : KMCommand( parent, msg ), mParent( parent ), mAttachments( attachments ), mEncoded( encoded ) 01704 { 01705 // do not load the complete message but only parts 01706 mMessageComplete = msg->isComplete(); 01707 msg->setComplete( true ); 01708 setDeletesItself( true ); 01709 } 01710 01711 void KMSaveAttachmentsCommand::execute() 01712 { 01713 QPtrList<KMMessage> lst = retrievedMsgs(); 01714 if ( lst.count() == 1 ) // restore original complete state 01715 lst.first()->setComplete(mMessageComplete); 01716 if ( mAttachments.count() > 0 ) 01717 { 01718 saveAll( mAttachments ); 01719 return; 01720 } 01721 KMMessage *msg = 0; 01722 QPtrListIterator<KMMessage> itr( lst ); 01723 01724 while ( itr.current() ) { 01725 msg = itr.current(); 01726 ++itr; 01727 QCString type = msg->typeStr(); 01728 01729 int mainType = msg->type(); 01730 int mainSubType = msg->subtype(); 01731 DwBodyPart* mainBody = 0; 01732 DwBodyPart* firstBodyPart = msg->getFirstDwBodyPart(); 01733 if( !firstBodyPart ) { 01734 // ATTENTION: This definitely /should/ be optimized. 01735 // Copying the message text into a new body part 01736 // surely is not the most efficient way to go. 01737 // I decided to do so for being able to get a 01738 // solution working for old style (== non MIME) 01739 // mails without spending much time on implementing. 01740 // During code revisal when switching to KMime 01741 // all this will probably disappear anyway (or it 01742 // will be optimized, resp.). (khz, 6.12.2001) 01743 kdDebug(5006) << "*no* first body part found, creating one from Message" << endl; 01744 mainBody = new DwBodyPart( msg->asDwString(), 0 ); 01745 mainBody->Parse(); 01746 } 01747 partNode *rootNode = new partNode( mainBody, mainType, mainSubType, true ); 01748 rootNode->setFromAddress( msg->from() ); 01749 01750 if ( firstBodyPart ) { 01751 partNode* curNode = new partNode(firstBodyPart); 01752 rootNode->setFirstChild( curNode ); 01753 curNode->buildObjectTree(); 01754 } 01755 parse( rootNode ); 01756 } 01757 } 01758 01759 void KMSaveAttachmentsCommand::parse( partNode *rootNode ) 01760 { 01761 QPtrList<partNode> attachments; 01762 for( partNode *child = rootNode; child; child = child->firstChild() ) { 01763 for( partNode *tmp = child; tmp; tmp = tmp->nextSibling() ) { 01764 attachments.append( tmp ); 01765 } 01766 } 01767 saveAll( attachments ); 01768 } 01769 01770 void KMSaveAttachmentsCommand::saveAll( const QPtrList<partNode>& attachments ) 01771 { 01772 if ( attachments.isEmpty() ) { 01773 KMessageBox::information( 0, i18n("Found no attachments to save.") ); 01774 return; 01775 } 01776 mAttachments = attachments; 01777 // load all parts 01778 KMLoadPartsCommand *command = new KMLoadPartsCommand( mAttachments, retrievedMessage() ); 01779 connect( command, SIGNAL( partsRetrieved() ), 01780 this, SLOT( slotSaveAll() ) ); 01781 command->start(); 01782 } 01783 01784 void KMSaveAttachmentsCommand::slotSaveAll() 01785 { 01786 QPtrListIterator<partNode> itr( mAttachments ); 01787 01788 QString dir, file; 01789 if ( mAttachments.count() > 1 ) 01790 { 01791 // get the dir 01792 KFileDialog fdlg( QString::null, QString::null, mParent, 0, true ); 01793 fdlg.setMode( (unsigned int) KFile::Directory ); 01794 if ( !fdlg.exec() ) return; 01795 dir = fdlg.selectedURL().path(); 01796 } 01797 else { 01798 // only one item, get the desired filename 01799 // replace all ':' with '_' because ':' isn't allowed on FAT volumes 01800 QString s = 01801 (*itr)->msgPart().fileName().stripWhiteSpace().replace( ':', '_' ); 01802 if ( s.isEmpty() ) 01803 s = (*itr)->msgPart().name().stripWhiteSpace().replace( ':', '_' ); 01804 if ( s.isEmpty() ) 01805 s = "unnamed"; // ### this should probably be i18n'ed 01806 file = KFileDialog::getSaveFileName( s, QString::null, mParent, 01807 QString::null ); 01808 } 01809 01810 while ( itr.current() ) { 01811 QString s; 01812 QString filename; 01813 if ( !dir.isEmpty() ) { 01814 s = (*itr)->msgPart().fileName().stripWhiteSpace().replace( ':', '_' ); 01815 if ( s.isEmpty() ) 01816 s = (*itr)->msgPart().name().stripWhiteSpace().replace( ':', '_' ); 01817 // Check if it has the Content-Disposition... filename: header 01818 // to make sure it's an actual attachment 01819 // we can't do the check earlier as we first need to load the mimeheader 01820 // for imap attachments to do this check 01821 if ( s.isEmpty() ) { 01822 ++itr; 01823 continue; 01824 } 01825 filename = dir + "/" + s; 01826 } 01827 else 01828 filename = file; 01829 01830 if( !filename.isEmpty() ) { 01831 if( QFile::exists( filename ) ) { 01832 if( KMessageBox::warningYesNo( mParent, 01833 i18n( "A file named %1 already exists. Do you want to overwrite it?" ).arg( s.isEmpty() ? filename : s ), 01834 i18n( "KMail Warning" ) ) == 01835 KMessageBox::No ) { 01836 ++itr; 01837 continue; 01838 } 01839 } 01840 saveItem( itr.current(), filename ); 01841 } 01842 ++itr; 01843 } 01844 } 01845 01846 void KMSaveAttachmentsCommand::saveItem( partNode *node, const QString& filename ) 01847 { 01848 if ( node && !filename.isEmpty() ) { 01849 bool bSaveEncrypted = false; 01850 bool bEncryptedParts = node->encryptionState() != KMMsgNotEncrypted; 01851 if( bEncryptedParts ) 01852 if( KMessageBox::questionYesNo( mParent, 01853 i18n( "This part of the message is encrypted. Do you want to keep the encryption when saving?" ), 01854 i18n( "KMail Question" ) ) == 01855 KMessageBox::Yes ) 01856 bSaveEncrypted = true; 01857 01858 bool bSaveWithSig = true; 01859 if( node->signatureState() != KMMsgNotSigned ) 01860 if( KMessageBox::questionYesNo( mParent, 01861 i18n( "This part of the message is signed. Do you want to keep the signature when saving?" ), 01862 i18n( "KMail Question" ) ) != 01863 KMessageBox::Yes ) 01864 bSaveWithSig = false; 01865 01866 QFile file( filename ); 01867 if( file.open( IO_WriteOnly ) ) { 01868 fchmod( file.handle(), S_IRUSR | S_IWUSR ); 01869 if ( mEncoded ) 01870 { 01871 // This does not decode the Message Content-Transfer-Encoding 01872 // but saves the _original_ content of the message part 01873 QDataStream ds( &file ); 01874 QCString cstr( node->msgPart().body() ); 01875 ds.writeRawBytes( cstr, cstr.size() ); 01876 } 01877 else 01878 { 01879 QDataStream ds( &file ); 01880 if( bSaveEncrypted || !bEncryptedParts) { 01881 partNode *dataNode = node; 01882 if( !bSaveWithSig ) { 01883 if( DwMime::kTypeMultipart == node->type() && 01884 DwMime::kSubtypeSigned == node->subType() ){ 01885 // carefully look for the part that is *not* the signature part: 01886 if( node->findType( DwMime::kTypeApplication, 01887 DwMime::kSubtypePgpSignature, 01888 TRUE, false ) ){ 01889 dataNode = node->findTypeNot( DwMime::kTypeApplication, 01890 DwMime::kSubtypePgpSignature, 01891 TRUE, false ); 01892 }else if( node->findType( DwMime::kTypeApplication, 01893 DwMime::kSubtypePkcs7Mime, 01894 TRUE, false ) ){ 01895 dataNode = node->findTypeNot( DwMime::kTypeApplication, 01896 DwMime::kSubtypePkcs7Mime, 01897 TRUE, false ); 01898 }else{ 01899 dataNode = node->findTypeNot( DwMime::kTypeMultipart, 01900 DwMime::kSubtypeUnknown, 01901 TRUE, false ); 01902 } 01903 } 01904 } 01905 QByteArray cstr = dataNode->msgPart().bodyDecodedBinary(); 01906 size_t size = cstr.size(); 01907 if ( dataNode->msgPart().type() == DwMime::kTypeText ) { 01908 // convert CRLF to LF before writing text attachments to disk 01909 size = KMFolder::crlf2lf( cstr.data(), size ); 01910 } 01911 ds.writeRawBytes( cstr.data(), size ); 01912 } 01913 } 01914 file.close(); 01915 } else 01916 // FIXME: After string freeze is over: 01917 // KMessageBox::error( mParent, 01918 // i18n( "%1 is detailed error description", 01919 // "Could not write the file:\n%1" ) 01920 // .arg( QString::fromLocal8Bit( strerror( errno ) ) ), 01921 // i18n( "KMail Error" ) ); 01922 KMessageBox::error( mParent, 01923 i18n( "Could not write the file." ) + "\n" 01924 + QString::fromLocal8Bit( strerror( errno ) ), 01925 i18n( "KMail Error" ) ); 01926 } 01927 } 01928 01929 KMLoadPartsCommand::KMLoadPartsCommand( QPtrList<partNode>& parts, KMMessage *msg ) 01930 : mParts( parts ), mNeedsRetrieval( 0 ), mMsg( msg ) 01931 { 01932 } 01933 01934 KMLoadPartsCommand::KMLoadPartsCommand( partNode* node, KMMessage *msg ) 01935 : mNeedsRetrieval( 0 ), mMsg( msg ) 01936 { 01937 mParts.append( node ); 01938 } 01939 01940 void KMLoadPartsCommand::start() 01941 { 01942 QPtrListIterator<partNode> it( mParts ); 01943 while ( it.current() ) 01944 { 01945 if ( !it.current()->msgPart().isComplete() && 01946 !it.current()->msgPart().partSpecifier().isEmpty() ) 01947 { 01948 // incomplete part so retrieve it first 01949 ++mNeedsRetrieval; 01950 KMFolder* curFolder = mMsg->parent(); 01951 if ( curFolder ) 01952 { 01953 FolderJob *job = curFolder->createJob( mMsg, FolderJob::tGetMessage, 01954 0, it.current()->msgPart().partSpecifier() ); 01955 connect( job, SIGNAL(messageUpdated(KMMessage*, QString)), 01956 this, SLOT(slotPartRetrieved(KMMessage*, QString)) ); 01957 job->start(); 01958 } else 01959 kdWarning(5006) << "KMLoadPartsCommand - msg has no parent" << endl; 01960 } 01961 ++it; 01962 } 01963 if ( mNeedsRetrieval == 0 ) 01964 execute(); 01965 } 01966 01967 void KMLoadPartsCommand::slotPartRetrieved( KMMessage* msg, QString partSpecifier ) 01968 { 01969 DwBodyPart* part = msg->findDwBodyPart( msg->getFirstDwBodyPart(), partSpecifier ); 01970 if ( part ) 01971 { 01972 // update the DwBodyPart in the partNode 01973 QPtrListIterator<partNode> it( mParts ); 01974 while ( it.current() ) 01975 { 01976 if ( it.current()->dwPart() == part ) 01977 it.current()->setDwPart( part ); 01978 ++it; 01979 } 01980 } else 01981 kdWarning(5006) << "KMLoadPartsCommand::slotPartRetrieved - could not find bodypart!" << endl; 01982 --mNeedsRetrieval; 01983 if ( mNeedsRetrieval == 0 ) 01984 execute(); 01985 } 01986 01987 void KMLoadPartsCommand::execute() 01988 { 01989 emit partsRetrieved(); 01990 delete this; 01991 } 01992
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:57:58 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003