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