diff --git a/Makefile.am b/Makefile.am index f4a53cf79..f22910d9e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -74,7 +74,7 @@ libkmailcommon_la_SOURCES = kmmessage.cpp kmmainwin.cpp configuredialog.cpp \ maildirjob.cpp mboxjob.cpp imapjob.cpp \ subscriptiondialog.cpp kmailicalifaceimpl.cpp aboutdata.cpp \ folderIface.cpp folderIface.skel mailserviceimpl.cpp \ - attachmentlistview.cpp + attachmentlistview.cpp kmail_SOURCES = main.cpp @@ -91,7 +91,7 @@ noinst_HEADERS = adddirectoryservicedialogimpl.h kmmimeparttree.h \ signatureconfigurationdialogimpl.h \ encryptionconfigurationdialogimpl.h \ signatureconfigurationdialogimpl.h \ - kmailicalifaceimpl.h mailserviceimpl.h + kmailicalifaceimpl.h mailserviceimpl.h dcoptest_SOURCES = dcoptest.cpp kmailIface.skel mailcomposerIface.skel diff --git a/kmcommands.cpp b/kmcommands.cpp index 7841a057d..494d27f3c 100644 --- a/kmcommands.cpp +++ b/kmcommands.cpp @@ -149,7 +149,8 @@ void KMCommand::slotPostTransfer(bool success) if (msg->parent()) msg->setTransferInProgress(false); } - delete this; + if ( !deletesItself() ) + delete this; } void KMCommand::transferSelectedMsgs() @@ -516,11 +517,24 @@ void KMShowMsgSrcCommand::execute() KMSaveMsgCommand::KMSaveMsgCommand( QWidget *parent, const QPtrList &msgList ) - :KMCommand( parent, msgList ) + :KMCommand( parent ), mTotalSize( 0 ) { if (!msgList.getFirst()) return; + setDeletesItself( true ); KMMsgBase *msgBase = msgList.getFirst(); + + // We operate on serNums and not the KMMsgBase pointers, as those can + // change, or become invalid when changing the current message, switching + // folders, etc. + QPtrListIterator it(msgList); + while ( it.current() ) { + mMsgList.append( (*it)->getMsgSerNum() ); + mTotalSize += (*it)->msgSize(); + (*it)->parent()->open(); + ++it; + } + mMsgListIndex = 0; QString subject = msgBase->subject(); while (subject.find(':') != -1) subject = subject.mid(subject.find(':') + 1).stripWhiteSpace(); @@ -535,21 +549,127 @@ KURL KMSaveMsgCommand::url() void KMSaveMsgCommand::execute() { -//TODO: Handle messages one by one - QPtrList msgList = retrievedMsgs(); - QCString str; - if (!msgList.getFirst()) + mJob = KIO::put( mUrl, -1, false, false ); + mJob->slotTotalSize( mTotalSize ); + mJob->setAsyncDataEnabled( true ); + mJob->setReportDataSent( true ); + connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)), + SLOT(slotSaveDataReq())); + connect(mJob, SIGNAL(result(KIO::Job*)), + SLOT(slotSaveResult(KIO::Job*))); +} + +void KMSaveMsgCommand::slotSaveDataReq() +{ + int remainingBytes = mData.size() - mOffset; + if ( remainingBytes > 0 ) { + // eat leftovers first + if ( remainingBytes > MAX_CHUNK_SIZE ) + remainingBytes = MAX_CHUNK_SIZE; + + QByteArray data; + data.duplicate( mData + mOffset, remainingBytes ); + mJob->sendAsyncData( mData ); + mOffset += remainingBytes; return; + } + // No leftovers, process next message. + if ( mMsgListIndex < mMsgList.size() ) { + KMMessage *msg = 0; + int idx = -1; + KMFolder * p = 0; + kernel->msgDict()->getLocation( mMsgList[mMsgListIndex], &p, &idx ); + assert( p ); + assert( idx >= 0 ); + msg = p->getMsg(idx); + + if (msg->transferInProgress()) { + QByteArray data = QByteArray(); + mJob->sendAsyncData( data ); + } + msg->setTransferInProgress( true ); + if (msg->isComplete() ) { + slotMessageRetrievedForSaving(msg); + } else { + // retrieve Message first + if (msg->parent() && !msg->isComplete() ) { + FolderJob *job = msg->parent()->createJob(msg); + connect(job, SIGNAL(messageRetrieved(KMMessage*)), + this, SLOT(slotMessageRetrievedForSaving(KMMessage*))); + job->start(); + } + } + } else { + // No more messages. Tell the putjob we are done. + QByteArray data = QByteArray(); + mJob->sendAsyncData( data ); + } +} - for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) { - str += "From " + msg->fromEmail() + " " + msg->dateShortStr() + "\n"; - str += msg->asString(); - str += "\n"; +void KMSaveMsgCommand::slotMessageRetrievedForSaving(KMMessage *msg) +{ + QCString str; + str += "From " + msg->fromEmail() + " " + msg->dateShortStr() + "\n"; + str += msg->asString(); + str += "\n"; + msg->setTransferInProgress(false); + + mData = str; + mData.resize(mData.size() - 1); + mOffset = 0; + QByteArray data; + int size; + // Unless it is great than 64 k send the whole message. kio buffers for us. + if( mData.size() > (unsigned int) MAX_CHUNK_SIZE ) + size = MAX_CHUNK_SIZE; + else + size = mData.size(); + + data.duplicate( mData, size ); + mJob->sendAsyncData( data ); + mOffset += size; + ++mMsgListIndex; + // Get rid of the message. + if (msg->parent()) { + int idx = -1; + KMFolder * p = 0; + kernel->msgDict()->getLocation( msg, &p, &idx ); + assert( p == msg->parent() ); assert( idx >= 0 ); + p->unGetMsg( idx ); + p->close(); } +} - QByteArray ba = str; - ba.resize(ba.size() - 1); - kernel->byteArrayToRemoteFile(ba, mUrl); +void KMSaveMsgCommand::slotSaveResult(KIO::Job *job) +{ + if (job->error()) + { + if (job->error() == KIO::ERR_FILE_ALREADY_EXIST) + { + if (KMessageBox::warningContinueCancel(0, + i18n("File %1 exists.\nDo you want to replace it?") + .arg(mUrl.prettyURL()), i18n("Save to file"), i18n("&Replace")) + == KMessageBox::Continue) { + mMsgListIndex = 0; + + mJob = KIO::put( mUrl, -1, true, false ); + mJob->slotTotalSize( mTotalSize ); + mJob->setAsyncDataEnabled( true ); + mJob->setReportDataSent( true ); + connect(mJob, SIGNAL(dataReq(KIO::Job*, QByteArray &)), + SLOT(slotSaveDataReq())); + connect(mJob, SIGNAL(result(KIO::Job*)), + SLOT(slotSaveResult(KIO::Job*))); + } + } + else + { + job->showErrorDialog(); + delete this; + } + } else { + delete this; + } } //TODO: ReplyTo, NoQuoteReplyTo, ReplyList, ReplyToAll are all similar diff --git a/kmcommands.h b/kmcommands.h index d97e09246..01bbbe89c 100644 --- a/kmcommands.h +++ b/kmcommands.h @@ -37,6 +37,11 @@ public: KMCommand( QWidget *parent, KMMsgBase *msgBase ); virtual ~KMCommand(); + bool deletesItself () { return mDeletesItself; } + void setDeletesItself( bool deletesItself ) + { mDeletesItself = deletesItself; } + + public slots: // Retrieve messages then calls execute void start(); @@ -65,7 +70,6 @@ private slots: void slotJobFinished(); /** the transfer was cancelled */ void slotTransferCancelled(); - signals: void messagesTransfered(bool); @@ -75,6 +79,7 @@ private: //Currently only one async command allowed at a time static int mCountJobs; int mCountMsgs; + bool mDeletesItself; QWidget *mParent; QPtrList mRetrievedMsgs; @@ -249,8 +254,21 @@ public: private: virtual void execute(); +private slots: + void slotSaveDataReq(); + void slotSaveResult(KIO::Job *job); + /** the message has been transferred for saving */ + void slotMessageRetrievedForSaving(KMMessage *msg); + private: + static const int MAX_CHUNK_SIZE = 64*1024; KURL mUrl; + QValueList mMsgList; + unsigned int mMsgListIndex; + QByteArray mData; + int mOffset; + size_t mTotalSize; + KIO::TransferJob *mJob; }; class KMReplyToCommand : public KMCommand