From 4d95134b13ac95e159cf1b17377620c90b55a60e Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Wed, 12 Apr 2023 12:06:04 -0400 Subject: [PATCH] 2023-04-12 Fred Gleason * Added 'RDReplicator::roundDownToDow()' methods. * Added a 'Westwood One Wegener Portal' replicator. Signed-off-by: Fred Gleason --- ChangeLog | 3 + lib/rdreplicator.cpp | 20 ++ lib/rdreplicator.h | 4 +- rdrepld/Makefile.am | 6 +- rdrepld/rdrepld.cpp | 83 ++++---- rdrepld/ww1ipump.cpp | 462 +++++++++++++++++++++++++++++++++++++++++++ rdrepld/ww1ipump.h | 44 +++++ 7 files changed, 580 insertions(+), 42 deletions(-) create mode 100644 rdrepld/ww1ipump.cpp create mode 100644 rdrepld/ww1ipump.h diff --git a/ChangeLog b/ChangeLog index 3f9a82ea..fc4ba2a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24023,3 +24023,6 @@ * Incremented the package version to 4.0.0rc2int0. 2023-04-12 Fred Gleason * Added a 'RDUpload::createDestinationDirs()' method. +2023-04-12 Fred Gleason + * Added 'RDReplicator::roundDownToDow()' methods. + * Added a 'Westwood One Wegener Portal' replicator. diff --git a/lib/rdreplicator.cpp b/lib/rdreplicator.cpp index 76a303a9..41ef3a94 100644 --- a/lib/rdreplicator.cpp +++ b/lib/rdreplicator.cpp @@ -205,6 +205,10 @@ QString RDReplicator::typeString(RDReplicator::Type type) ret="Citadel X-Digital Portal"; break; + case RDReplicator::TypeWw1Ipump: + ret="Westwood One Wegener Portal"; + break; + case RDReplicator::TypeLast: break; } @@ -212,6 +216,22 @@ QString RDReplicator::typeString(RDReplicator::Type type) } +QDate RDReplicator::roundDownToDow(const QDate &date,int dow) +{ + return date.addDays(-(date.dayOfWeek()-dow)); +} + + +QDateTime RDReplicator::roundDownToDow(const QDateTime &dt,int dow) +{ + QDateTime ret=dt; + + ret.setDate(RDReplicator::roundDownToDow(dt.date(),dow)); + + return ret; +} + + QVariant RDReplicator::GetValue(const QString &field) const { QVariant ret; diff --git a/lib/rdreplicator.h b/lib/rdreplicator.h index c4a5eb40..23d80a3f 100644 --- a/lib/rdreplicator.h +++ b/lib/rdreplicator.h @@ -28,7 +28,7 @@ class RDReplicator { public: - enum Type {TypeCitadelXds=0,TypeLast=1}; + enum Type {TypeCitadelXds=0,TypeWw1Ipump=1,TypeLast=2}; RDReplicator(const QString &name); QString name() const; RDReplicator::Type type() const; @@ -58,6 +58,8 @@ class RDReplicator int normalizeLevel() const; void setNormalizeLevel(int lvl) const; QString typeString() const; + static QDate roundDownToDow(const QDate &date,int dow); + static QDateTime roundDownToDow(const QDateTime &dt,int dow); static QString typeString(RDReplicator::Type type); private: diff --git a/rdrepld/Makefile.am b/rdrepld/Makefile.am index 28ccadd7..b62353ff 100644 --- a/rdrepld/Makefile.am +++ b/rdrepld/Makefile.am @@ -1,6 +1,6 @@ ## Makefile.am ## -## (C) Copyright 2010-2022 Fred Gleason +## (C) Copyright 2010-2023 Fred Gleason ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License version 2 as @@ -15,7 +15,6 @@ ## License along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ## -## ## Use automake to process this into a Makefile.in AM_CPPFLAGS = -Wall -I$(top_srcdir)/lib -Wno-strict-aliasing -std=c++11 -fPIC @QT5_CFLAGS@ @MUSICBRAINZ_CFLAGS@ @IMAGEMAGICK_CFLAGS@ @@ -30,7 +29,8 @@ sbin_PROGRAMS = rdrepld dist_rdrepld_SOURCES = rdrepld.cpp rdrepld.h \ replconfig.cpp replconfig.h\ replfactory.cpp replfactory.h\ - citadelxds.cpp citadelxds.h + citadelxds.cpp citadelxds.h\ + ww1ipump.cpp ww1ipump.h nodist_rdrepld_SOURCES = moc_rdrepld.cpp rdrepld_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT5_LIBS@ @MUSICBRAINZ_LIBS@ @IMAGEMAGICK_LIBS@ diff --git a/rdrepld/rdrepld.cpp b/rdrepld/rdrepld.cpp index 4c2cb498..c6bcdfd5 100644 --- a/rdrepld/rdrepld.cpp +++ b/rdrepld/rdrepld.cpp @@ -2,7 +2,7 @@ // // The Rivendell Replicator Daemon // -// (C) Copyright 2010-2021 Fred Gleason +// (C) Copyright 2010-2023 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -36,6 +36,7 @@ #include "citadelxds.h" #include "rdrepld.h" +#include "ww1ipump.h" void SigHandler(int signum) { @@ -149,47 +150,49 @@ void MainObject::ProcessCarts() RDEscapeString(q->value(0).toString())+"')||"; } delete q; - where=where.left(where.length()-2); - sql=QString("select ")+ - "`NUMBER`,"+ // 00 - "`TYPE`,"+ // 01 - "`METADATA_DATETIME` "+ // 02 - "from `CART` where "+ - where; - q=new RDSqlQuery(sql); - while(q->next()) { + where=where.left(where.length()-2).trimmed(); + if(!where.isEmpty()) { sql=QString("select ")+ - "`ID`,"+ // 00 - "`ITEM_DATETIME` "+ // 01 - "from `REPL_CART_STATE` where "+ - "(`REPLICATOR_NAME`='"+RDEscapeString(repl_name)+"')&&"+ - QString::asprintf("(`CART_NUMBER`=%u)",q->value(0).toUInt()); - q1=new RDSqlQuery(sql); - if(q1->first()) { - stale=q->value(2).toDateTime()>q1->value(1).toDateTime(); - } - else { - stale=true; - } - if(stale) { - if(repl_replicators[i]->processCart(q->value(0).toUInt())) { - if(q1->isValid()) { - sql=QString("update `REPL_CART_STATE` set ")+ - "`ITEM_DATETIME`=now() where "+ - QString::asprintf("`ID`=%u",q1->value(0).toUInt()); - } - else { - sql=QString("insert into `REPL_CART_STATE` set ")+ - "`REPLICATOR_NAME`='"+RDEscapeString(repl_name)+"',"+ - QString::asprintf("`CART_NUMBER`=%u,",q->value(0).toUInt())+ - "`ITEM_DATETIME`=now()"; - } - RDSqlQuery::apply(sql); + "`NUMBER`,"+ // 00 + "`TYPE`,"+ // 01 + "`METADATA_DATETIME` "+ // 02 + "from `CART` where "+ + where; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString("select ")+ + "`ID`,"+ // 00 + "`ITEM_DATETIME` "+ // 01 + "from `REPL_CART_STATE` where "+ + "(`REPLICATOR_NAME`='"+RDEscapeString(repl_name)+"')&&"+ + QString::asprintf("(`CART_NUMBER`=%u)",q->value(0).toUInt()); + q1=new RDSqlQuery(sql); + if(q1->first()) { + stale=q->value(2).toDateTime()>q1->value(1).toDateTime(); } + else { + stale=true; + } + if(stale) { + if(repl_replicators[i]->processCart(q->value(0).toUInt())) { + if(q1->isValid()) { + sql=QString("update `REPL_CART_STATE` set ")+ + "`ITEM_DATETIME`=now() where "+ + QString::asprintf("`ID`=%u",q1->value(0).toUInt()); + } + else { + sql=QString("insert into `REPL_CART_STATE` set ")+ + "`REPLICATOR_NAME`='"+RDEscapeString(repl_name)+"',"+ + QString::asprintf("`CART_NUMBER`=%u,",q->value(0).toUInt())+ + "`ITEM_DATETIME`=now()"; + } + RDSqlQuery::apply(sql); + } + } + delete q1; } - delete q1; + delete q; } - delete q; } } @@ -236,6 +239,10 @@ void MainObject::LoadReplicators() repl_replicators.push_back(new CitadelXds(config)); break; + case RDReplicator::TypeWw1Ipump: + repl_replicators.push_back(new Ww1Ipump(config)); + break; + case RDReplicator::TypeLast: break; } diff --git a/rdrepld/ww1ipump.cpp b/rdrepld/ww1ipump.cpp new file mode 100644 index 00000000..8748b362 --- /dev/null +++ b/rdrepld/ww1ipump.cpp @@ -0,0 +1,462 @@ +// ww1ipump.cpp +// +// Replicator implementation for the Westwood One iPump Replicator +// +// (C) Copyright 2010-2023 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ww1ipump.h" + +#define RD_MAX_CART_NUMBER 999999 + +Ww1Ipump::Ww1Ipump(ReplConfig *repl_config) + : ReplFactory(repl_config) +{ + QString sql; + RDSqlQuery *q; + + sql="select `LAST_ISCI_XREFERENCE` from `VERSION`"; + q=new RDSqlQuery(sql); + if(q->first()) { + xds_isci_datetime=q->value(0).toDateTime(); + } + delete q; +} + + +void Ww1Ipump::startProcess() +{ + CheckIsciXreference(); + CheckCarts(); +} + + +bool Ww1Ipump::processCart(const unsigned cartnum) +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + + sql=QString::asprintf("select `FILENAME` from `ISCI_XREFERENCE` \ + where (`CART_NUMBER`=%u)&&(`LATEST_DATE`>=now())&&\ + ((`TYPE`='R')||(`TYPE`='B'))",cartnum); + q=new RDSqlQuery(sql); + if(q->first()) { + ret=PostCut(RDCut::cutName(cartnum,1),q->value(0).toString()); + } + delete q; + return ret; +} + + +void Ww1Ipump::CheckIsciXreference() +{ + QString sql; + + QFileInfo *fi=new QFileInfo(rda->system()->isciXreferencePath()); + if(fi->exists()) { + if(fi->lastModified()>xds_isci_datetime) { + if(LoadIsciXreference(rda->system()->isciXreferencePath())) { + sql="update `VERSION` set `LAST_ISCI_XREFERENCE`=now()"; + RDSqlQuery::apply(sql); + xds_isci_datetime=QDateTime(QDate::currentDate(),QTime::currentTime()); + PurgeCuts(); + } + } + } + else { + rda->syslog(LOG_WARNING,"unable to load ISCI cross reference file \"%s\"", + (const char *)rda->system()->isciXreferencePath().toUtf8()); + } + delete fi; +} + + +bool Ww1Ipump::LoadIsciXreference(const QString &filename) +{ + FILE *f=NULL; + char line[1024]; + QString sql; + RDSqlQuery *q; + RDStringList fields; + unsigned cartnum; + QStringList datelist; + QDate date; + bool ok=false; + unsigned linenum=3; + + if((f=fopen(filename.toUtf8(),"r"))==NULL) { + rda->syslog(LOG_WARNING, + "unable to load ISCI cross reference file \"%s\" [%s]", + (const char *)rda->system()->isciXreferencePath().toUtf8(), + strerror(errno)); + return false; + } + + // + // Purge Old Data + // + sql="delete from `ISCI_XREFERENCE`"; + q=new RDSqlQuery(sql); + delete q; + + // + // Skip Header + // + if(fgets(line,1024,f)==NULL) { + rda->syslog(LOG_WARNING,"fgets() error reading ISCI xreference data"); + } + if(fgets(line,1024,f)==NULL) { + rda->syslog(LOG_WARNING,"fgets() error reading ISCI xreference data"); + } + + // + // Load Records + // + while(fgets(line,1024,f)!=NULL) { + fields=fields.split(',',line,"\""); + if(fields.size()==9) { + for(int i=0;isyslog(LOG_WARNING,"invalid date in line %d of \"%s\"", + linenum,(const char *)filename.toUtf8()); + } + } + else { + rda->syslog(LOG_WARNING, + "invalid FILENAME field \"%s\" in line %d of \"%s\"", + (const char *)fields[8].toUtf8(),linenum, + (const char *)filename.toUtf8()); + } + } + else { + rda->syslog(LOG_WARNING,"invalid date in line %d of \"%s\"", + linenum,(const char *)filename.toUtf8()); + } + } + else { + rda->syslog(LOG_DEBUG, + "missing/invalid cart number in line %d of \"%s\"", + linenum,(const char *)filename.toUtf8()); + } + } + else { + rda->syslog(LOG_WARNING,"line %d malformed in \"%s\"", + linenum,(const char *)filename.toUtf8()); + } + linenum++; + } + + // + // Clean Up + // + rda->syslog(LOG_INFO,"loaded ISCI cross reference file \"%s\"", + (const char *)rda->system()->isciXreferencePath().toUtf8()); + fclose(f); + return true; +} + + +bool Ww1Ipump::ValidateFilename(const QString &filename) +{ + bool ret=true; + + // + // List of illegal characters taken from 'Illegal Characters4.doc' + // from Citadel + // + ret=ret&&(filename.indexOf(" ")<0); + ret=ret&&(filename.indexOf("\"")<0); + ret=ret&&(filename.indexOf("%")<0); + ret=ret&&(filename.indexOf("*")<0); + ret=ret&&(filename.indexOf("+")<0); + ret=ret&&(filename.indexOf("/")<0); + ret=ret&&(filename.indexOf(":")<0); + ret=ret&&(filename.indexOf(";")<0); + ret=ret&&(filename.indexOf("<")<0); + ret=ret&&(filename.indexOf("=")<0); + ret=ret&&(filename.indexOf(">")<0); + ret=ret&&(filename.indexOf("?")<0); + ret=ret&&(filename.indexOf("@")<0); + ret=ret&&(filename.indexOf("[")<0); + ret=ret&&(filename.indexOf("\\")<0); + ret=ret&&(filename.indexOf("]")<0); + ret=ret&&(filename.indexOf("^")<0); + ret=ret&&(filename.indexOf("{")<0); + ret=ret&&(filename.indexOf("|")<0); + ret=ret&&(filename.indexOf("}")<0); + + return ret; +} + + +void Ww1Ipump::CheckCarts() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDSqlQuery *q2; + QString now=QDateTime(QDate::currentDate(),QTime::currentTime()).addDays(-6). + toString("yyyy-MM-dd hh:mm:ss"); + + // + // Generate Update List + // + sql=QString("select ")+ + "`CART_NUMBER`,"+ // 00 + "`FILENAME` "+ // 01 + "from `ISCI_XREFERENCE` where "+ + "(`LATEST_DATE`>=now())&&((`TYPE`='R')||(`TYPE`='B'))"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString("select `REPL_CART_STATE`.`ID` from ")+ + "`REPL_CART_STATE` left join `CUTS` "+ + "on `REPL_CART_STATE`.`CART_NUMBER`=`CUTS`.`CART_NUMBER` where "+ + "(`CUTS`.`ORIGIN_DATETIME`<`REPL_CART_STATE`.`ITEM_DATETIME`)&&"+ + "(`REPL_CART_STATE`.`REPLICATOR_NAME`='"+ + RDEscapeString(config()->name())+"')&&"+ + QString::asprintf("(`REPL_CART_STATE`.`CART_NUMBER`=%u)&&", + q->value(0).toUInt())+ + "(`REPL_CART_STATE`.`POSTED_FILENAME`='"+ + RDEscapeString(q->value(1).toString())+"')&&"+ + "(`REPL_CART_STATE`.`ITEM_DATETIME`>'"+RDEscapeString(now)+"')&&"+ + "(`REPL_CART_STATE`.`REPOST`='N')"; + q1=new RDSqlQuery(sql); + if(!q1->first()) { + if(PostCut(RDCut::cutName(q->value(0).toUInt(),1), + q->value(1).toString())) { + sql=QString("select `ID` from `REPL_CART_STATE` where ")+ + "(`REPLICATOR_NAME`='"+RDEscapeString(config()->name())+"')&&"+ + QString::asprintf("(`CART_NUMBER`=%u)&&",q->value(0).toUInt())+ + "(`POSTED_FILENAME`='"+RDEscapeString(q->value(1).toString())+"')"; + q2=new RDSqlQuery(sql); + if(q2->first()) { + sql=QString("update `REPL_CART_STATE` set ")+ + "`ITEM_DATETIME`=now(),"+ + "`REPOST`='N' where "+ + "(`REPLICATOR_NAME`='"+RDEscapeString(config()->name())+"')&&"+ + QString::asprintf("(`CART_NUMBER`=%u)&&",q->value(0).toUInt())+ + "(`POSTED_FILENAME`='"+RDEscapeString(q->value(1).toString())+"')"; + } + else { + sql=QString("insert into `REPL_CART_STATE` set ")+ + "`ITEM_DATETIME`=now(),"+ + "`REPOST`='N',"+ + "`REPLICATOR_NAME`='"+RDEscapeString(config()->name())+"',"+ + QString::asprintf("`CART_NUMBER`=%u,",q->value(0).toUInt())+ + "`POSTED_FILENAME`='"+RDEscapeString(q->value(1).toString())+"'"; + } + delete q2; + RDSqlQuery::apply(sql); + } + } + delete q1; + } + delete q; +} + + +bool Ww1Ipump::PostCut(const QString &cutname,const QString &filename) +{ + // + // Export File + // + RDAudioConvert::ErrorCode conv_err; + RDUpload::ErrorCode upload_err; + float speed_ratio=1.0; + RDCut *cut=new RDCut(cutname); + if(!cut->exists()) { + delete cut; + return false; + } + if(cut->length()==0) { + delete cut; + return true; + } + RDCart *cart=new RDCart(cut->cartNumber()); + if(cart->enforceLength()) { + speed_ratio=(float)cut->length()/(float)cart->forcedLength(); + } + RDSettings *settings=new RDSettings(); + QString tempfile=RDTempDirectory::basePath()+"/"+filename; + RDAudioConvert *conv=new RDAudioConvert(); + conv->setSourceFile(RDCut::pathName(cutname)); + conv->setDestinationFile(tempfile); + conv->setRange(cut->startPoint(),cut->endPoint()); + conv->setSpeedRatio(speed_ratio); + settings->setFormat(config()->format()); + settings->setChannels(config()->channels()); + settings->setSampleRate(config()->sampleRate()); + settings->setBitRate(config()->bitRate()); + settings->setQuality(config()->quality()); + settings->setNormalizationLevel(config()->normalizeLevel()/1000); + conv->setDestinationSettings(settings); + delete cart; + delete cut; + switch(conv_err=conv->convert()) { + case RDAudioConvert::ErrorOk: + break; + + default: + rda->syslog(LOG_WARNING, + "Ww1Ipump: audio conversion failed: %s, cutname: %s", + (const char *)RDAudioConvert::errorText(conv_err).toUtf8(), + (const char *)cutname.toUtf8()); + delete conv; + delete settings; + return false; + } + delete conv; + delete settings; + + // + // Upload File + // + QDate monday=RDReplicator::roundDownToDow(QDate::currentDate(),1); + QString err_msg; + RDUpload *upload=new RDUpload(rda->config()); + upload->setSourceFile(tempfile); + QString dest_url=config()->url(); + if(dest_url.right(1)!="/") { + dest_url+="/"; + } + dest_url+="Spots/"+ + QString::asprintf("%d/WEEK OF ",monday.year())+ + monday.toString("MMddyy")+"/"+filename; + upload->setDestinationUrl(dest_url); + upload->createDestinationDirs(true); + + // + // FIXME: Finish implementing ssh(1) id keys! + // + switch(upload_err=upload->runUpload(config()->urlUsername(), + config()->urlPassword(),"",false,&err_msg, + rda->config()->logXloadDebugData())) { + case RDUpload::ErrorOk: + break; + + default: + rda->syslog(LOG_WARNING,"Ww1Ipump: audio upload failed: %s", + err_msg.toUtf8().constData()); + unlink(tempfile.toUtf8()); + delete upload; + return false; + } + unlink(tempfile.toUtf8()); + delete upload; + rda->syslog(LOG_INFO,"Ww1Ipump: uploaded cut %s to %s", + cutname.toUtf8().constData(), + dest_url.toUtf8().constData()); + + return true; +} + + +void Ww1Ipump::PurgeCuts() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDSqlQuery *q2; + RDDelete *conv; + RDDelete::ErrorCode conv_err; + + sql=QString("select ")+ + "`ID`,"+ // 00 + "`POSTED_FILENAME` "+ // 01 + "from `REPL_CART_STATE` where "+ + "`REPLICATOR_NAME`='"+RDEscapeString(config()->name())+"'"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString("select `ID` from `ISCI_XREFERENCE` where ")+ + "`FILENAME`='"+RDEscapeString(q->value(1).toString())+"'"; + q1=new RDSqlQuery(sql); + if(!q1->first()) { + QString path=config()->url(); + if(path.right(1)!="/") { + path+="/"; + } + QUrl url(path+q->value(1).toString()); + conv=new RDDelete(rda->config()); + conv->setTargetUrl(url.toString()); + // + // FIXME: Finish implementing ssh(1) key support! + // + if((conv_err=conv->runDelete(config()->urlUsername(), + config()->urlPassword(),"",false, + rda->config()->logXloadDebugData()))== + RDDelete::ErrorOk) { + sql=QString::asprintf("delete from `REPL_CART_STATE` where `ID`=%d", + q->value(0).toInt()); + q2=new RDSqlQuery(sql); + delete q2; + rda->syslog(LOG_INFO,"purged \"%s\" for replicator \"%s\"", + (const char *)url.toString().toUtf8(), + (const char *)config()->name().toUtf8()); + } + else { + rda->syslog(LOG_WARNING, + "unable to delete \"%s\" for replicator \"%s\" [%s]", + (const char *)url.toString().toUtf8(), + (const char *)config()->name().toUtf8(), + (const char *)RDDelete::errorText(conv_err).toUtf8()); + } + delete conv; + } + delete q1; + } + delete q; +} diff --git a/rdrepld/ww1ipump.h b/rdrepld/ww1ipump.h new file mode 100644 index 00000000..8c52a456 --- /dev/null +++ b/rdrepld/ww1ipump.h @@ -0,0 +1,44 @@ +// ww1ipump.h +// +// Replicator implementation for the Westwood One iPump Replicator +// +// (C) Copyright 2010-2023 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WW1IPUMP_H +#define WW1IPUMP_H + +#include "replfactory.h" + +class Ww1Ipump : public ReplFactory +{ + public: + Ww1Ipump(ReplConfig *repl_config); + void startProcess(); + bool processCart(const unsigned cartnum); + + private: + void CheckIsciXreference(); + bool LoadIsciXreference(const QString &filename); + bool ValidateFilename(const QString &filename); + void CheckCarts(); + bool PostCut(const QString &cutname,const QString &filename); + void PurgeCuts(); + QDateTime xds_isci_datetime; +}; + + +#endif // WW1IPUMP_H