kpilot/kpilot

hotSync.cc

00001 /* KPilot
00002 **
00003 ** Copyright (C) 2001 by Dan Pilone
00004 ** Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00005 ** Copyright (C) 2006 Adriaan de Groot <groot@kde.org>
00006 **
00007 ** This file defines SyncActions, which are used to perform some specific
00008 ** task during a HotSync. Conduits are not included here, nor are
00009 ** sync actions requiring user interaction. Those can be found in the
00010 ** conduits subdirectory or interactiveSync.h.
00011 */
00012 
00013 /*
00014 ** This program is free software; you can redistribute it and/or modify
00015 ** it under the terms of the GNU General Public License as published by
00016 ** the Free Software Foundation; either version 2 of the License, or
00017 ** (at your option) any later version.
00018 **
00019 ** This program is distributed in the hope that it will be useful,
00020 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00022 ** GNU General Public License for more details.
00023 **
00024 ** You should have received a copy of the GNU General Public License
00025 ** along with this program in a file called COPYING; if not, write to
00026 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00027 ** MA 02110-1301, USA.
00028 */
00029 
00030 /*
00031 ** Bug reports and questions can be sent to kde-pim@kde.org.
00032 */
00033 
00034 
00035 #include "options.h"
00036 
00037 #include <time.h>
00038 #include <unistd.h>
00039 #include <stdio.h>
00040 
00041 #include <pi-file.h>
00042 #include <pi-util.h>
00043 
00044 #include <qtimer.h>
00045 #include <qfile.h>
00046 #include <qfileinfo.h>
00047 #include <qdir.h>
00048 #include <qvaluelist.h>
00049 #include <qregexp.h>
00050 #include <qstringlist.h>
00051 
00052 #include <kglobal.h>
00053 #include <kstandarddirs.h>
00054 #include <kapplication.h>
00055 
00056 #include "pilotUser.h"
00057 #include "pilotRecord.h"
00058 #include "syncStack.h"
00059 #include "pilotSerialDatabase.h"
00060 #include "pilotLocalDatabase.h"
00061 #include "pilotDatabase.h"
00062 #include "kpilotSettings.h"
00063 
00064 #include "hotSync.moc"
00065 
00066 TestLink::TestLink(KPilotLink * p) :
00067     SyncAction(p, "testLink")
00068 {
00069     FUNCTIONSETUP;
00070 
00071 }
00072 
00073 /* virtual */ bool TestLink::exec()
00074 {
00075     FUNCTIONSETUP;
00076 
00077     int i;
00078     int dbindex = 0;
00079     int count = 0;
00080     struct DBInfo db;
00081 
00082     addSyncLogEntry(i18n("Testing.\n"));
00083 
00084     while ((i = deviceLink()->getNextDatabase(dbindex,&db)) > 0)
00085     {
00086         count++;
00087         dbindex = db.index + 1;
00088 
00089         DEBUGKPILOT << fname
00090             << ": Read database " << db.name
00091             << " with index " << db.index
00092             << endl;
00093 
00094         // Let the Pilot User know what's happening
00095         openConduit();
00096         // Let the KDE User know what's happening
00097         // Pretty sure all database names are in latin1.
00098         emit logMessage(i18n("Syncing database %1...")
00099             .arg(Pilot::fromPilot(db.name)));
00100 
00101         kapp->processEvents();
00102     }
00103 
00104     emit logMessage(i18n("HotSync finished."));
00105     emit syncDone(this);
00106     return true;
00107 }
00108 
00109 class BackupAction::Private
00110 {
00111 public:
00112     Private() : fTimer(0L) { }
00113 
00114     QTimer *fTimer;
00115     bool fFullBackup;
00116     QStringList fNoBackupDBs;
00117     QValueList<unsigned long> fNoBackupCreators;
00118     QStringList fDeviceDBs;
00119 
00120     QString fPreferBackupDir; 
00122     // Remainder is used to hand around info during sync
00123 
00124     int fDBIndex;       
00125     QString fBackupDir; 
00126 } ;
00127 
00128 BackupAction::BackupAction(KPilotLink * p, bool full) :
00129     SyncAction(p, "backupAction"),
00130     fP( new Private )
00131 {
00132     FUNCTIONSETUP;
00133 
00134     fP->fFullBackup = full;
00135 }
00136 
00137 /* virtual */ QString BackupAction::statusString() const
00138 {
00139     FUNCTIONSETUP;
00140     QString s(CSL1("BackupAction="));
00141 
00142     switch (status())
00143     {
00144     case Init:
00145         s.append(CSL1("Init"));
00146         break;
00147     case Error:
00148         s.append(CSL1("Error"));
00149         break;
00150     case FullBackup:
00151         s.append(CSL1("FullBackup"));
00152         break;
00153     case FastBackup:
00154         s.append(CSL1("FastBackup"));
00155         break;
00156     case BackupEnded:
00157         s.append(CSL1("BackupEnded"));
00158         break;
00159     case BackupIncomplete:
00160         s.append(CSL1("BackupIncomplete"));
00161         break;
00162     case BackupComplete:
00163         s.append(CSL1("BackupComplete"));
00164         break;
00165     default:
00166         s.append(CSL1("(unknown "));
00167         s.append(QString::number(status()));
00168         s.append(CSL1(")"));
00169     }
00170 
00171     return s;
00172 }
00173 
00174 void BackupAction::setDirectory( const QString &p )
00175 {
00176     fP->fPreferBackupDir = p;
00177     if (!p.endsWith(CSL1("/")))
00178     {
00179         fP->fPreferBackupDir.append(CSL1("/"));
00180     }
00181 }
00182 
00183 static inline bool dontBackup(struct DBInfo *info,
00184     const QStringList &dbnames,
00185     const QValueList<unsigned long> &dbcreators)
00186 {
00187     // Special case - skip database Unsaved Preferences
00188     if (   (info->creator == pi_mktag('p','s','y','s'))  &&
00189         (info->type == pi_mktag('p','r','e','f')) ) return true;
00190 
00191     if (dbcreators.findIndex(info->creator) != -1) return true;
00192 
00193     // Now take wildcards into account
00194     QString db = Pilot::fromPilot(info->name);
00195     for (QStringList::const_iterator i = dbnames.begin(); i != dbnames.end(); ++i)
00196     {
00197         QRegExp re(*i,true,true); // Wildcard match
00198         if (re.exactMatch(db)) return true;
00199     }
00200     return false;
00201 }
00202 
00203 static inline void initNoBackup(QStringList &dbnames,
00204     QValueList<unsigned long> &dbcreators)
00205 {
00206     FUNCTIONSETUP;
00207     dbnames.clear();
00208     dbcreators.clear();
00209 
00210     QStringList configuredSkip = KPilotSettings::skipBackupDB();
00211     QStringList::const_iterator e = configuredSkip.end();
00212     for (QStringList::const_iterator i = configuredSkip.begin();
00213         i!= e; ++i)
00214     {
00215         QString s = *i;
00216         if (s.startsWith(CSL1("[")) && s.endsWith(CSL1("]")))
00217         {
00218             if (s.length() != 6)
00219             {
00220                 kdWarning() << k_funcinfo << ": Creator ID " << s << " is malformed." << endl;
00221             }
00222             else
00223             {
00224                 QCString data =  s.mid(1,4).latin1();
00225                 unsigned long creator = pi_mktag(data[0],data[1],data[2],data[3]);
00226                 dbcreators.append(creator);
00227             }
00228         }
00229         else
00230         {
00231             dbnames.append(s);
00232         }
00233     }
00234 
00235     DEBUGKPILOT << fname << ": Will skip databases "
00236         << dbnames.join(CSL1(",")) << endl;
00237     QString creatorids;
00238     for (QValueList<unsigned long>::const_iterator i = dbcreators.begin();
00239         i != dbcreators.end(); ++i)
00240     {
00241         creatorids.append(CSL1("[%1]").arg(*i,0,16));
00242     }
00243     DEBUGKPILOT << fname << ": Will skip creators " << creatorids << endl;
00244 }
00245 
00246 /* virtual */ bool BackupAction::exec()
00247 {
00248     FUNCTIONSETUP;
00249 
00250     fP->fDeviceDBs = KPilotSettings::deviceDBs();
00251 
00252     if (fP->fPreferBackupDir.isEmpty())
00253     {
00254         fP->fBackupDir =
00255             KGlobal::dirs()->saveLocation("data",CSL1("kpilot/DBBackup/")) +
00256             Pilot::fromPilot(deviceLink()->getPilotUser().getUserName()) +
00257             CSL1("/");
00258     }
00259     else
00260     {
00261         fP->fBackupDir = fP->fPreferBackupDir;
00262     }
00263 
00264     logMessage(i18n("Backup directory: %1.").arg(fP->fBackupDir));
00265 
00266     DEBUGKPILOT << fname
00267         << ": This Pilot user's name is \""
00268         << deviceLink()->getPilotUser().getUserName() << "\"" << endl;
00269     DEBUGKPILOT << fname
00270         << ": Using backup dir: " << fP->fBackupDir << endl;
00271     DEBUGKPILOT << fname
00272         << ": Full Backup? " << fP->fFullBackup << endl;
00273 
00274 
00275     if (fP->fFullBackup)
00276     {
00277         fActionStatus = FullBackup;
00278         addSyncLogEntry(i18n("Full backup started."));
00279     }
00280     else
00281     {
00282         fActionStatus = FastBackup;
00283         addSyncLogEntry(i18n("Fast backup started"));
00284     }
00285 
00286     if (!checkBackupDirectory(fP->fBackupDir))
00287     {
00288         fActionStatus=BackupIncomplete;
00289         // Don't issue an error message, checkBackupDirectory
00290         // did this already...
00291         return false;
00292     }
00293 
00294     initNoBackup( fP->fNoBackupDBs, fP->fNoBackupCreators );
00295 
00296     fP->fTimer = new QTimer( this );
00297     QObject::connect( fP->fTimer, SIGNAL( timeout() ),
00298         this, SLOT( backupOneDB() ) );
00299 
00300     fP->fDBIndex = 0;
00301 
00302     fP->fTimer->start( 0, false );
00303     return true;
00304 }
00305 
00306 bool BackupAction::checkBackupDirectory( const QString &backupDir )
00307 {
00308     FUNCTIONSETUP;
00309     QFileInfo fi(backupDir);
00310 
00311     if (fi.exists() && fi.isDir())
00312     {
00313         return true;
00314     }
00315 
00316     if (fi.exists() && !fi.isDir())
00317     {
00318         kdWarning() << k_funcinfo
00319             << ": Requested backup directory "
00320             << backupDir
00321             << " exists but is not a directory."
00322             << endl;
00323         return false;
00324     }
00325 
00326     if ( !backupDir.endsWith("/") )
00327     {
00328         kdWarning() << k_funcinfo
00329             << ": Backup dir does not end with a / "
00330             << endl;
00331         return false;
00332     }
00333 
00334     Q_ASSERT(!fi.exists());
00335 
00336     DEBUGKPILOT << fname
00337         << ": Creating directory " << backupDir << endl;
00338 
00339     KStandardDirs::makeDir( backupDir );
00340 
00341     fi = QFileInfo(backupDir);
00342 
00343     return fi.exists() && fi.isDir();
00344 }
00345 
00346 /* slot */ void BackupAction::backupOneDB()
00347 {
00348     FUNCTIONSETUP;
00349 
00350     struct DBInfo info;
00351 
00352     emit logProgress(QString::null, fP->fDBIndex);
00353 
00354     if (openConduit() < 0)
00355     {
00356         addSyncLogEntry(i18n("Exiting on cancel."));
00357         endBackup();
00358         fActionStatus = BackupIncomplete;
00359         return;
00360     }
00361 
00362     // TODO: Is there a way to skip unchanged databases?
00363     int res = deviceLink()->getNextDatabase( fP->fDBIndex, &info );
00364     if (res < 0)
00365     {
00366         if ( fP->fFullBackup )
00367             addSyncLogEntry( i18n("Full backup complete.") );
00368         else
00369             addSyncLogEntry( i18n("Fast backup complete.") );
00370         endBackup();
00371         fActionStatus = BackupComplete;
00372         return;
00373     }
00374 
00375     fP->fDBIndex = info.index + 1;
00376 
00377     char buff[8];
00378     memset(buff, 0, 8);
00379     buff[0] = '[';
00380     set_long( &buff[1], info.creator );
00381     buff[5] = ']';
00382     buff[6] = '\0';
00383     QString creator = QString::fromLatin1( buff );
00384     info.name[33]='\0';
00385     QString dbname = QString::fromLatin1( info.name );
00386     if ( !fP->fDeviceDBs.contains( creator ) )
00387         fP->fDeviceDBs << creator;
00388     if ( !fP->fDeviceDBs.contains( dbname ) )
00389         fP->fDeviceDBs << dbname;
00390 
00391 
00392     DEBUGKPILOT << fname << ": Checking to see if we should backup database " << info.name
00393         << " [" << QString::number(info.creator,16) << "]" << endl;
00394 
00395     // see if user told us not to back this creator or database up...
00396     if (dontBackup(&info,fP->fNoBackupDBs,fP->fNoBackupCreators))
00397     {
00398         DEBUGKPILOT << fname << ": Skipping database " << info.name
00399             << " (database in no-backup list)" << endl;
00400         QString s = i18n("Skipping %1")
00401             .arg(Pilot::fromPilot(info.name));
00402         addSyncLogEntry(s);
00403         return;
00404     }
00405 
00406     // don't backup resource databases...
00407     if ( (!fP->fFullBackup) && PilotDatabase::isResource(&info))
00408     {
00409         DEBUGKPILOT << fname << ": Skipping database " << info.name
00410             << " (resource database)" << endl;
00411         // Just skip resource DBs during an update hotsync.
00412         return;
00413     }
00414 
00415     QString s = i18n("Backing up: %1")
00416         .arg(Pilot::fromPilot(info.name));
00417     addSyncLogEntry(s);
00418 
00419     if (!createLocalDatabase(&info))
00420     {
00421         kdError() << k_funcinfo
00422             << ": Couldn't create local database for "
00423             << info.name << endl;
00424         addSyncLogEntry(i18n("Backup of %1 failed.\n")
00425             .arg(Pilot::fromPilot(info.name)));
00426     }
00427     else
00428     {
00429         addSyncLogEntry(i18n(" .. OK\n"),false); // Not in kpilot log.
00430     }
00431 }
00432 
00442 bool BackupAction::createLocalDatabase(DBInfo * info)
00443 {
00444     FUNCTIONSETUP;
00445 
00446     QString databaseName(Pilot::fromPilot(info->name));
00447     // default this to true.  we will set it to false if there are no modified
00448     // records and we are not doing a full sync.
00449     bool doBackup = true;
00450 
00451     // make sure that our directory is available...
00452     if (!checkBackupDirectory( fP->fBackupDir )) return false;
00453 
00454     // we always need to open the database on the pilot because if we're going to sync
00455     // it, we need to reset the "dirty" flags, etc.
00456     PilotDatabase *serial=deviceLink()->database(databaseName);
00457     if (!serial->isOpen())
00458     {
00459         DEBUGKPILOT << fname << ": Unable to open database "<<info->name
00460             << " to check for modified records and reset sync flags." << endl;
00461         KPILOT_DELETE(serial);
00462         return false;
00463     }
00464 
00465     // now we look to see if the database on the pilot has at least one changed record
00466     // in it.  we do this so that we don't waste time backing up a database that has
00467     // not changed.  note: don't bother with this check if we're doing a full backup.
00468     if (!fP->fFullBackup && serial->isOpen())
00469     {
00470         int index=0;
00471         PilotRecord*rec=serial->readNextModifiedRec(&index);
00472         if (!rec)
00473         {
00474             doBackup = false;
00475         }
00476         KPILOT_DELETE(rec);
00477     }
00478 
00479     // close this database with the Pilot so we can back it up to the
00480     // filesystem if necessary
00481     KPILOT_DELETE(serial);
00482 
00483     // if we don't need to do a backup for this database, clean up and
00484     // return true (our work here is done)
00485     if (!doBackup)
00486     {
00487 #ifdef DEBUG
00488         DEBUGDB << fname
00489             << ": don't need to backup this database (no changes)." << endl;
00490 #endif
00491         return true;
00492     }
00493 
00494     // if we're here then we are going to back this database up.  do some basic sanity
00495     // checks and proceed....
00496     databaseName.replace('/', CSL1("_"));
00497 
00498     QString fullBackupName = fP->fBackupDir + databaseName;
00499 
00500     if (PilotDatabase::isResource(info))
00501     {
00502         fullBackupName.append(CSL1(".prc"));
00503     }
00504     else
00505     {
00506         fullBackupName.append(CSL1(".pdb"));
00507     }
00508 
00509 #ifdef DEBUG
00510     DEBUGDB << fname
00511         << ": Backing up database to: [" << fullBackupName << "]" << endl;
00512 #endif
00513 
00514     /* Ensure that DB-open flag is not kept */
00515     info->flags &= ~dlpDBFlagOpen;
00516 
00517     bool backedUp = fHandle->retrieveDatabase(fullBackupName,info);
00518 
00519     // if we've backed this one up, clean it up so we won't do it again next
00520     // sync unless it's truly changed
00521     serial=deviceLink()->database(databaseName);
00522     if (backedUp && serial->isOpen())
00523     {
00524         serial->cleanup();
00525         serial->resetSyncFlags();
00526     }
00527     KPILOT_DELETE(serial);
00528 
00529     return backedUp;
00530 }
00531 
00532 void BackupAction::endBackup()
00533 {
00534     FUNCTIONSETUP;
00535 
00536     KPILOT_DELETE(fP->fTimer);
00537     fP->fDBIndex = (-1);
00538     fActionStatus = BackupEnded;
00539     fP->fDeviceDBs.sort();
00540     QString old( QString::null );
00541     QStringList::Iterator itr = fP->fDeviceDBs.begin();
00542     while ( itr != fP->fDeviceDBs.end() ) {
00543         if ( old == *itr ) {
00544             itr = fP->fDeviceDBs.remove( itr );
00545         } else {
00546             old = *itr;
00547             ++itr;
00548         }
00549     }
00550     KPilotSettings::setDeviceDBs( fP->fDeviceDBs );
00551 
00552     emit syncDone(this);
00553 }
00554 
00555 FileInstallAction::FileInstallAction(KPilotLink * p,
00556     const QString & d) :
00557     SyncAction(p, "fileInstall"),
00558     fDBIndex(-1),
00559     fTimer(0L),
00560     fDir(d)
00561 {
00562     FUNCTIONSETUP;
00563 }
00564 
00565 FileInstallAction::~FileInstallAction()
00566 {
00567     FUNCTIONSETUP;
00568 
00569     KPILOT_DELETE(fTimer);
00570 }
00571 
00572 /* virtual */ bool FileInstallAction::exec()
00573 {
00574     FUNCTIONSETUP;
00575 
00576     QDir installDir(fDir);
00577     fList = installDir.entryList(QDir::Files |
00578         QDir::NoSymLinks | QDir::Readable);
00579 #ifdef DEBUG
00580     DEBUGKPILOT << fname
00581         << ": Installing " << fList.count() << " files" << endl;
00582 #endif
00583 
00584     fDBIndex = 0;
00585     emit logMessage(i18n("[File Installer]"));
00586 
00587     // Possibly no files to install?
00588     if (!fList.count())
00589     {
00590         emit logMessage(i18n("No Files to install"));
00591         delayDone();
00592         return true;
00593     }
00594 
00595     fTimer = new QTimer(this);
00596     QObject::connect(fTimer, SIGNAL(timeout()),
00597         this, SLOT(installNextFile()));
00598 
00599     fTimer->start(0, false);
00600 
00601     emit logProgress(i18n("Installing one file",
00602         "Installing %n Files",fList.count()), 0);
00603     return true;
00604 }
00605 
00606 /* slot */ void FileInstallAction::installNextFile()
00607 {
00608     FUNCTIONSETUP;
00609 
00610     Q_ASSERT(fDBIndex >= 0);
00611     Q_ASSERT((unsigned) fDBIndex <= fList.count());
00612 
00613 #ifdef DEBUG
00614     DEBUGKPILOT << fname
00615         << ": Installing file index "
00616         << fDBIndex << " (of " << fList.count() << ")" << endl;
00617 #endif
00618 
00619     if ((!fList.count()) || ((unsigned) fDBIndex >= fList.count()))
00620     {
00621 #ifdef DEBUG
00622         DEBUGKPILOT << fname
00623             << ": Peculiar file index, bailing out." << endl;
00624 #endif
00625         KPILOT_DELETE(fTimer);
00626         fDBIndex = (-1);
00627         emit logProgress(i18n("Done Installing Files"), 100);
00628         delayDone();
00629         return;
00630     }
00631 
00632     const QString filePath = fDir + fList[fDBIndex];
00633     const QString fileName = fList[fDBIndex];
00634 
00635     fDBIndex++;
00636 
00637 #ifdef DEBUG
00638     DEBUGKPILOT << fname << ": Installing file " << filePath << endl;
00639 #endif
00640 
00641     QString m = i18n("Installing %1").arg(fileName);
00642     emit logProgress(m,(100 * fDBIndex) / (fList.count()+1));
00643     m+=CSL1("\n");
00644     emit addSyncLogEntry(m,false /* Don't print in KPilot's log. */ );
00645 
00646     struct pi_file *f = 0L;
00647 
00648     // Check DB is ok, return false after warning user
00649     if (!resourceOK(fileName,filePath)) goto nextFile;
00650 
00651     f = pi_file_open(const_cast <char *>
00652         ((const char *) QFile::encodeName(filePath)));
00653 
00654 
00655 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
00656     if (pi_file_install(f, pilotSocket(), 0) < 0)
00657 #else
00658     if (pi_file_install(f, pilotSocket(), 0, NULL) < 0)
00659 #endif
00660     {
00661         kdWarning() << k_funcinfo << ": failed to install." << endl;
00662 
00663 
00664         emit logError(i18n("Cannot install file &quot;%1&quot;.").
00665             arg(fileName));
00666     }
00667     else
00668     {
00669         QFile::remove(filePath);
00670     }
00671 
00672 
00673 nextFile:
00674     if (f) pi_file_close(f);
00675     if (fDBIndex == -1)
00676     {
00677         fTimer->stop();
00678         delayDone();
00679         // emit syncDone(this);
00680     }
00681 }
00682 
00683 // Check that the given file path is a good resource
00684 // file - in particular that the resource name is ok.
00685 bool FileInstallAction::resourceOK(const QString &fileName, const QString &filePath)
00686 {
00687     FUNCTIONSETUP;
00688 
00689     if (!QFile::exists(filePath))
00690     {
00691         emit logError(i18n("Unable to open file &quot;%1&quot;.").
00692             arg(fileName));
00693         return false;
00694     }
00695 
00696     struct pi_file *f = pi_file_open(const_cast <char *>
00697         ((const char *) QFile::encodeName(filePath)));
00698 
00699     if (!f)
00700     {
00701         emit logError(i18n("Unable to open file &quot;%1&quot;.").
00702             arg(fileName));
00703         return false;
00704     }
00705 
00706     struct DBInfo info;
00707 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
00708     if (pi_file_get_info(f,&info) < 0)
00709     {
00710         emit logError(i18n("Unable to read file &quot;%1&quot;.").
00711             arg(fileName));
00712         return false;
00713     }
00714 #else
00715     pi_file_get_info(f,&info);
00716 #endif
00717 
00718     // Looks like strlen, but we can't be sure of a NUL
00719     // termination.
00720     info.name[sizeof(info.name)-1]=0;
00721     bool r = (strlen(info.name) < 32);
00722     pi_file_close(f);
00723 
00724     if (!r)
00725     {
00726         emit logError(i18n("The database in &quot;%1&quot; has a "
00727             "resource name that is longer than 31 characters. "
00728             "This suggests a bug in the tool used to create the database. "
00729             "KPilot cannot install this database.").arg(fileName));
00730     }
00731 
00732     return r;
00733 }
00734 
00735 /* virtual */ QString FileInstallAction::statusString() const
00736 {
00737     FUNCTIONSETUP;
00738     if (fDBIndex < 0)
00739     {
00740         return QString(CSL1("Idle"));
00741     }
00742     else
00743     {
00744         if ((unsigned) fDBIndex >= fList.count())
00745         {
00746             return QString(CSL1("Index out of range"));
00747         }
00748         else
00749         {
00750             return QString(CSL1("Installing %1")).arg(fList[fDBIndex]);
00751         }
00752     }
00753 }
00754 
00755 CleanupAction::CleanupAction(KPilotLink *p)  : SyncAction(p,"cleanupAction")
00756 {
00757     FUNCTIONSETUP;
00758 }
00759 
00760 CleanupAction::~CleanupAction()
00761 {
00762 #ifdef DEBUG
00763     FUNCTIONSETUP;
00764     DEBUGKPILOT << fname
00765         << ": Deleting @" << (long)this << endl;
00766 #endif
00767 }
00768 
00769 /* virtual */ bool CleanupAction::exec()
00770 {
00771     FUNCTIONSETUP;
00772 
00773     if (deviceLink())
00774     {
00775         deviceLink()->finishSync();
00776     }
00777     emit syncDone(this);
00778     return true;
00779 }
00780 
00781 
KDE Home | KDE Accessibility Home | Description of Access Keys