diff options
Diffstat (limited to 'knode/knconvert.cpp')
-rw-r--r-- | knode/knconvert.cpp | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/knode/knconvert.cpp b/knode/knconvert.cpp new file mode 100644 index 000000000..40461139b --- /dev/null +++ b/knode/knconvert.cpp @@ -0,0 +1,447 @@ +/* + KNode, the KDE newsreader + Copyright (c) 1999-2005 the KNode authors. + See file AUTHORS for details + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US +*/ + +#include <qlayout.h> +#include <qwidgetstack.h> +#include <qlabel.h> +#include <qcheckbox.h> + +#include <klocale.h> +#include <kfiledialog.h> +#include <kseparator.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <klineedit.h> +#include <kprocess.h> +#include <kapplication.h> +#include <kpushbutton.h> + +#include <kmime_util.h> + +#include "knconvert.h" +#include "resource.h" + + +bool KNConvert::needToConvert(const QString &oldVersion) +{ + bool ret=( + (oldVersion.left(3)=="0.3") || + (oldVersion.left(3)=="0.4") + ); + + return ret; +} + + +KNConvert::KNConvert(const QString &version) + : QDialog(0,0,true), l_ogList(0), c_onversionDone(false), v_ersion(version) +{ + setCaption(kapp->makeStdCaption(i18n("Conversion"))); + QVBoxLayout *topL=new QVBoxLayout(this, 5,5); + s_tack=new QWidgetStack(this); + topL->addWidget(s_tack, 1); + topL->addWidget(new KSeparator(this)); + + QHBoxLayout *btnL=new QHBoxLayout(topL, 5); + s_tartBtn=new QPushButton(i18n("Start Conversion..."), this); + s_tartBtn->setDefault(true); + btnL->addStretch(1); + btnL->addWidget(s_tartBtn); + c_ancelBtn=new KPushButton(KStdGuiItem::cancel(), this); + btnL->addWidget(c_ancelBtn); + + connect(s_tartBtn, SIGNAL(clicked()), this, SLOT(slotStart())); + connect(c_ancelBtn, SIGNAL(clicked()), this, SLOT(reject())); + + w_1=new QWidget(s_tack); + s_tack->addWidget(w_1, 1); + QGridLayout *w1L=new QGridLayout(w_1, 5,3, 5,5); + + QLabel *l1=new QLabel(i18n( +"<b>Congratulations, you have upgraded to KNode version %1.</b><br>\ +Unfortunately this version uses a different format for some data-files, so \ +in order to keep your existing data it is necessary to convert it first. This is \ +now done automatically by KNode. If you want to, a backup of your existing data \ +will be created before the conversion starts.").arg(KNODE_VERSION), w_1); + w1L->addMultiCellWidget(l1, 0,0, 0,2); + + c_reateBkup=new QCheckBox(i18n("Create backup of old data"), w_1); + w1L->addMultiCellWidget(c_reateBkup, 2,2, 0,2); + connect(c_reateBkup, SIGNAL(toggled(bool)), this, SLOT(slotCreateBkupToggled(bool))); + + b_ackupPathLabel=new QLabel(i18n("Save backup in:"), w_1); + w1L->addWidget(b_ackupPathLabel, 3,0); + + b_ackupPath=new KLineEdit(QDir::homeDirPath()+QString("/knodedata-")+v_ersion+".tar.gz", w_1); + w1L->addWidget(b_ackupPath, 3,1); + + b_rowseBtn= new QPushButton(i18n("Browse..."), w_1); + connect(b_rowseBtn, SIGNAL(clicked()), this, SLOT(slotBrowse())); + w1L->addWidget(b_rowseBtn, 3,2); + w1L->setColStretch(1,1); + w1L->addRowSpacing(1,15); + w1L->setRowStretch(4,1); + w1L->addRowSpacing(4,15); + + w_2=new QLabel(s_tack); + w_2->setText(i18n("<b>Converting, please wait...</b>")); + w_2->setAlignment(AlignCenter); + s_tack->addWidget(w_2, 2); + + w_3=new QWidget(s_tack); + s_tack->addWidget(w_3, 3); + QVBoxLayout *w3L=new QVBoxLayout(w_3, 5,5); + + r_esultLabel=new QLabel(w_3); + w3L->addWidget(r_esultLabel); + QLabel *l2=new QLabel(i18n("Processed tasks:"), w_3); + l_ogList=new QListBox(w_3); + w3L->addSpacing(15); + w3L->addWidget(l2); + w3L->addWidget(l_ogList, 1); + + s_tack->raiseWidget(w_1); + slotCreateBkupToggled(false); +} + + +KNConvert::~KNConvert() +{ + for ( QValueList<Converter*>::Iterator it = mConverters.begin(); it != mConverters.end(); ++it ) + delete (*it); +} + + +void KNConvert::convert() +{ + int errors=0; + for ( QValueList<Converter*>::Iterator it = mConverters.begin(); it != mConverters.end(); ++it ) + if( !(*it)->doConvert() ) + errors++; + + if(errors>0) + r_esultLabel->setText(i18n( +"<b>Some errors occurred during the conversion.</b>\ +<br>You should now examine the log to find out what went wrong.")); + else + r_esultLabel->setText(i18n( +"<b>The conversion was successful.</b>\ +<br>Have a lot of fun with this new version of KNode. ;-)")); + + s_tartBtn->setText(i18n("Start KNode")); + s_tartBtn->setEnabled(true); + c_ancelBtn->setEnabled(true); + l_ogList->insertStringList(l_og); + s_tack->raiseWidget(w_3); + + c_onversionDone=true; +} + + +void KNConvert::slotStart() +{ + if(c_onversionDone) { + accept(); + return; + } + + s_tartBtn->setEnabled(false); + c_ancelBtn->setEnabled(false); + s_tack->raiseWidget(w_2); + + if(v_ersion.left(3)=="0.3" || v_ersion.left(7)=="0.4beta") { + //Version 0.4 + mConverters.append( new Converter04( &l_og ) ); + } + + //create backup of old data using "tar" + if(c_reateBkup->isChecked()) { + if(b_ackupPath->text().isEmpty()) { + KMessageBox::error(this, i18n("Please select a valid backup path.")); + return; + } + + QString dataDir=locateLocal("data","knode/"); + t_ar=new KProcess; + *t_ar << "tar"; + *t_ar << "-cz" << dataDir + << "-f" << b_ackupPath->text(); + connect(t_ar, SIGNAL(processExited(KProcess*)), this, SLOT(slotTarExited(KProcess*))); + if(!t_ar->start()) { + delete t_ar; + t_ar = 0; + slotTarExited(0); + } + } + else + convert(); //convert files without backup +} + + +void KNConvert::slotCreateBkupToggled(bool b) +{ + b_ackupPathLabel->setEnabled(b); + b_ackupPath->setEnabled(b); + b_rowseBtn->setEnabled(b); +} + + +void KNConvert::slotBrowse() +{ + QString newPath=KFileDialog::getSaveFileName(b_ackupPath->text()); + + if(!newPath.isEmpty()) + b_ackupPath->setText(newPath); +} + + +void KNConvert::slotTarExited(KProcess *proc) +{ + bool success=true; + + if(!proc || !proc->normalExit() || proc->exitStatus()!=0) { + success=false; + if(KMessageBox::Cancel==KMessageBox::warningContinueCancel(this, i18n("<b>The backup failed</b>; do you want to continue anyway?"))) { + + delete t_ar; + t_ar = 0; + reject(); + return; + } + } + + delete t_ar; + t_ar = 0; + if(success) + l_og.append(i18n("created backup of the old data-files in %1").arg(b_ackupPath->text())); + else + l_og.append(i18n("backup failed.")); + + // now we actually convert the files + convert(); +} + + + +//============================================================================================ + + + +bool KNConvert::Converter04::doConvert() +{ + QString dir=locateLocal("data","knode/")+"folders/"; + int num; + bool error=false; + + //Drafts + if(QFile::exists(dir+"folder1.idx")) { + num=convertFolder(dir+"folder1", dir+"drafts_1"); + if(num==-1) { + error=true; + l_og->append(i18n("conversion of folder \"Drafts\" to version 0.4 failed.")); + } + else { + l_og->append(i18n("converted folder \"Drafts\" to version 0.4")); + } + } + else + l_og->append(i18n("nothing to be done for folder \"Drafts\"")); + + //Outbox + if(QFile::exists(dir+"folder2.idx")) { + num=convertFolder(dir+"folder2", dir+"outbox_2"); + if(num==-1) { + error=true; + l_og->append(i18n("conversion of folder \"Outbox\" to version 0.4 failed.")); + } + else { + l_og->append(i18n("converted folder \"Outbox\" to version 0.4")); + } + } + else + l_og->append(i18n("nothing to be done for folder \"Outbox\"")); + + //Sent + if(QFile::exists(dir+"folder3.idx")) { + num=convertFolder(dir+"folder3", dir+"sent_3"); + if(num==-1) { + error=true; + l_og->append(i18n("conversion of folder \"Sent\" to version 0.4 failed.")); + } + else { + l_og->append(i18n("converted folder \"Sent\" to version 0.4")); + } + } + else + l_og->append(i18n("nothing to be done for folder \"Sent\"")); + + //remove old info-files + QFile::remove(dir+"standard.info"); + QFile::remove(dir+".standard.info"); + return (!error); +} + + +int KNConvert::Converter04::convertFolder(QString srcPrefix, QString dstPrefix) +{ + QFile srcMBox(srcPrefix+".mbox"), + srcIdx(srcPrefix+".idx"), + dstMBox(dstPrefix+".mbox"), + dstIdx(dstPrefix+".idx"); + QTextStream ts(&dstMBox); + ts.setEncoding(QTextStream::Latin1); + + OldFolderIndex oldIdx; + NewFolderIndex newIdx; + int lastId=0; + bool filesOpen; + + //open files + filesOpen=srcMBox.open(IO_ReadOnly); + filesOpen=filesOpen && srcIdx.open(IO_ReadOnly); + + if(dstIdx.exists() && dstIdx.size()>0) { //we are converting from 0.4beta* + if( (filesOpen=filesOpen && dstIdx.open(IO_ReadOnly)) ) { + dstIdx.at( dstIdx.size()-sizeof(NewFolderIndex) ); //set filepointer to last entry + dstIdx.readBlock( (char*)(&newIdx), sizeof(NewFolderIndex) ); + lastId=newIdx.id; + dstIdx.close(); + } + } + + filesOpen=filesOpen && dstMBox.open(IO_WriteOnly | IO_Append); + filesOpen=filesOpen && dstIdx.open(IO_WriteOnly | IO_Append); + + if(!filesOpen) { + srcMBox.close(); + srcIdx.close(); + dstMBox.close(); + dstIdx.close(); + return -1; + } + + //conversion starts here + while(!srcIdx.atEnd()) { + + //read index data + srcIdx.readBlock( (char*)(&oldIdx), sizeof(OldFolderIndex)); + newIdx.id=++lastId; + newIdx.sId=oldIdx.sId; + newIdx.ti=oldIdx.ti; + + switch(oldIdx.status) { + case 0: //AStoPost + newIdx.flags[0]=false; //doMail() + newIdx.flags[1]=false; //mailed() + newIdx.flags[2]=true; //doPost() + newIdx.flags[3]=false; //posted() + newIdx.flags[4]=false; //canceled() + newIdx.flags[5]=false; //editDisabled() + break; + + case 1: //AStoMail + newIdx.flags[0]=true; //doMail() + newIdx.flags[1]=false; //mailed() + newIdx.flags[2]=false; //doPost() + newIdx.flags[3]=false; //posted() + newIdx.flags[4]=false; //canceled() + newIdx.flags[5]=false; //editDisabled() + break; + + case 2: //ASposted + newIdx.flags[0]=false; //doMail() + newIdx.flags[1]=false; //mailed() + newIdx.flags[2]=true; //doPost() + newIdx.flags[3]=true; //posted() + newIdx.flags[4]=false; //canceled() + newIdx.flags[5]=true; //editDisabled() + break; + + case 3: //ASmailed + newIdx.flags[0]=true; //doMail() + newIdx.flags[1]=true; //mailed() + newIdx.flags[2]=false; //doPost() + newIdx.flags[3]=false; //posted() + newIdx.flags[4]=false; //canceled() + newIdx.flags[5]=true; //editDisabled() + break; + + case 6: //AScanceled + newIdx.flags[0]=false; //doMail() + newIdx.flags[1]=false; //mailed() + newIdx.flags[2]=true; //doPost() + newIdx.flags[3]=true; //posted() + newIdx.flags[4]=true; //canceled() + newIdx.flags[5]=true; //editDisabled() + break; + + default: //what the .. + newIdx.flags[0]=false; //doMail() + newIdx.flags[1]=false; //mailed() + newIdx.flags[2]=false; //doPost() + newIdx.flags[3]=false; //posted() + newIdx.flags[4]=false; //canceled() + newIdx.flags[5]=false; //editDisabled() + break; + } + + + //read mbox-data + unsigned int size=oldIdx.eo-oldIdx.so; + QCString buff(size+10); + srcMBox.at(oldIdx.so); + int readBytes=srcMBox.readBlock(buff.data(), size); + buff.at(readBytes)='\0'; //terminate string; + + //remove "X-KNode-Overview" + int pos=buff.find('\n'); + if(pos>-1) + buff.remove(0, pos+1); + + //write mbox-data + ts << "From aaa@aaa Mon Jan 01 00:00:00 1997\n"; + newIdx.so=dstMBox.at(); //save start-offset + ts << "X-KNode-Overview: "; + ts << KMime::extractHeader(buff, "Subject") << '\t'; + ts << KMime::extractHeader(buff, "Newsgroups") << '\t'; + ts << KMime::extractHeader(buff, "To") << '\t'; + ts << KMime::extractHeader(buff, "Lines") << '\n'; + ts << buff; + newIdx.eo=dstMBox.at(); //save end-offset + ts << '\n'; + + //write index-data + dstIdx.writeBlock((char*)(&newIdx), sizeof(NewFolderIndex)); + } + + //close/remove files and return number of articles in the new folder + srcMBox.remove(); + srcIdx.remove(); + dstMBox.close(); + dstIdx.close(); + return ( dstIdx.size()/sizeof(NewFolderIndex) ); +} + + + + +//----------------------------- +#include "knconvert.moc" + + + + + + + |