/* KPilot ** ** Copyright (C) 2001 by Dan Pilone ** Copyright (C) 2003-2004 Reinhold Kainhofer ** Copyright (C) 2006 Adriaan de Groot ** ** This file defines SyncActions, which are used to perform some specific ** task during a HotSync. Conduits are not included here, nor are ** sync actions requiring user interaction. Those can be found in the ** conduits subdirectory or interactiveSync.h. */ /* ** 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. ** ** 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 in a file called COPYING; if not, write to ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ** MA 02110-1301, USA. */ /* ** Bug reports and questions can be sent to kde-pim@kde.org. */ #include "options.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pilotUser.h" #include "pilotRecord.h" #include "actionQueue.h" #include "pilotSerialDatabase.h" #include "pilotLocalDatabase.h" #include "pilotDatabase.h" #include "kpilotSettings.h" #include "hotSync.moc" class BackupAction::Thread : public TQThread { public: Thread( BackupAction *parent, KPilotLink *link, const TQString &filename, const DBInfo *info ); enum { TerminateOK = TQEvent::User, TerminateFailure } ; protected: virtual void run(); private: BackupAction *fParent; KPilotLink *fLink; TQString fFilename; struct DBInfo fDBInfo; } ; class BackupAction::Private { public: bool fFullBackup; ///< Is this a full backup (all DBs, not just changed ones)? TQStringList fNoBackupDBs; TQValueList fNoBackupCreators; TQStringList fDeviceDBs; TQString fPreferBackupDir; ///< Directory to write backup in, overrides default // Remainder is used to hand around info during sync int fDBIndex; ///< Database number we're now doing TQString fBackupDir; ///< Directory to write backup in. /** * Add the database described by the info block to the list of * databases definitely found on the handheld. */ void addDBInfo( const DBInfo *info ) { FUNCTIONSETUP; fDBIndex = info->index + 1; // Each character of buff[] is written to char buff[7]; buff[0] = '['; set_long( &buff[1], info->creator ); buff[5] = ']'; buff[6] = '\0'; TQString creator = TQString::fromLatin1( buff ); TQString dbname = Pilot::fromPilot( info->name, 32 ); if ( !fDeviceDBs.contains( creator ) ) { fDeviceDBs << creator; } if ( !fDeviceDBs.contains( dbname ) ) { fDeviceDBs << dbname; } DEBUGKPILOT << fname << ": Added <" << dbname << "> " << creator << endl; } /** * Check if this database, described by @p info , should * be backed up (i.e. is allowed to be backed up by the * user settings for no-backup DBs). * * @return @c true if the database may be backed up. */ bool allowBackup( const DBInfo *info ) const { // Special case - skip database Unsaved Preferences if ( (info->creator == pi_mktag('p','s','y','s')) && (info->type == pi_mktag('p','r','e','f')) ) { return false; } if (fNoBackupCreators.findIndex(info->creator) != -1) { return false; } // Now take wildcards into account TQString db = Pilot::fromPilot(info->name); for (TQStringList::const_iterator i = fNoBackupDBs.begin(); i != fNoBackupDBs.end(); ++i) { TQRegExp re(*i,true,true); // Wildcard match if (re.exactMatch(db)) { return false; } } return true; } } ; BackupAction::BackupAction(KPilotLink * p, bool full) : SyncAction(p, "backupAction"), fP( new Private ), fBackupThread( 0L ) { FUNCTIONSETUP; fP->fFullBackup = full; } /* virtual */ TQString BackupAction::statusString() const { FUNCTIONSETUP; TQString s(CSL1("BackupAction=")); switch (status()) { case Init: s.append(CSL1("Init")); break; case Error: s.append(CSL1("Error")); break; case FullBackup: s.append(CSL1("FullBackup")); break; case FastBackup: s.append(CSL1("FastBackup")); break; case BackupEnded: s.append(CSL1("BackupEnded")); break; case BackupIncomplete: s.append(CSL1("BackupIncomplete")); break; case BackupComplete: s.append(CSL1("BackupComplete")); break; default: s.append(CSL1("(unknown ")); s.append(TQString::number(status())); s.append(CSL1(")")); } return s; } void BackupAction::setDirectory( const TQString &p ) { fP->fPreferBackupDir = p; if (!p.endsWith(CSL1("/"))) { fP->fPreferBackupDir.append(CSL1("/")); } } static inline void initNoBackup(TQStringList &dbnames, TQValueList &dbcreators) { FUNCTIONSETUP; dbnames.clear(); dbcreators.clear(); TQStringList configuredSkip = KPilotSettings::skipBackupDB(); TQStringList::const_iterator e = configuredSkip.end(); for (TQStringList::const_iterator i = configuredSkip.begin(); i!= e; ++i) { TQString s = *i; if (s.startsWith(CSL1("[")) && s.endsWith(CSL1("]"))) { if (s.length() != 6) { WARNINGKPILOT << "Creator ID " << s << " is malformed." << endl; } else { TQCString data = s.mid(1,4).latin1(); unsigned long creator = pi_mktag(data[0],data[1],data[2],data[3]); dbcreators.append(creator); } } else { dbnames.append(s); } } DEBUGKPILOT << fname << ": Will skip databases " << dbnames.join(CSL1(",")) << endl; TQString creatorids; char buf[5]; for (TQValueList::const_iterator i = dbcreators.begin(); i != dbcreators.end(); ++i) { unsigned long tag = *i; pi_untag(buf,tag); buf[4]=0; creatorids.append(CSL1("[%1]").arg(buf)); } DEBUGKPILOT << fname << ": Will skip creators " << creatorids << endl; } /** Make sure that the backup directory @p backupDir * exists and is a directory; returns @c false * if this is not the case. This method will try * to create the directory if it doesn't exist yet. */ static inline bool checkBackupDirectory( const TQString &backupDir ) { FUNCTIONSETUP; TQFileInfo fi(backupDir); if (fi.exists() && fi.isDir()) { return true; } if (fi.exists() && !fi.isDir()) { WARNINGKPILOT << "Requested backup directory " << backupDir << " exists but is not a directory." << endl; return false; } if ( !backupDir.endsWith("/") ) { WARNINGKPILOT << "Backup dir does not end with a / " << endl; return false; } Q_ASSERT(!fi.exists()); DEBUGKPILOT << fname << ": Creating directory " << backupDir << endl; TDEStandardDirs::makeDir( backupDir ); fi = TQFileInfo(backupDir); return fi.exists() && fi.isDir(); } /* virtual */ bool BackupAction::exec() { FUNCTIONSETUP; fP->fDeviceDBs = KPilotSettings::deviceDBs(); if (fP->fPreferBackupDir.isEmpty()) { fP->fBackupDir = TDEGlobal::dirs()->saveLocation("data",CSL1("kpilot/DBBackup/")) + deviceLink()->getPilotUser().name() + '/'; } else { fP->fBackupDir = fP->fPreferBackupDir; } logMessage(i18n("Backup directory: %1.").arg(fP->fBackupDir)); DEBUGKPILOT << fname << ": This Pilot user's name is \"" << deviceLink()->getPilotUser().name() << "\"" << endl; DEBUGKPILOT << fname << ": Using backup dir: " << fP->fBackupDir << endl; DEBUGKPILOT << fname << ": Full Backup? " << fP->fFullBackup << endl; if (fP->fFullBackup) { fActionStatus = FullBackup; addSyncLogEntry(i18n("Full backup started.")); } else { fActionStatus = FastBackup; addSyncLogEntry(i18n("Fast backup started")); } if (!checkBackupDirectory(fP->fBackupDir)) { fActionStatus=BackupIncomplete; // Don't issue an error message, checkBackupDirectory // did this already... return false; } initNoBackup( fP->fNoBackupDBs, fP->fNoBackupCreators ); fP->fDBIndex = 0; TQTimer::singleShot(0,this,TQ_SLOT(backupOneDB())); return true; } /* slot */ void BackupAction::backupOneDB() { FUNCTIONSETUP; struct DBInfo info; // TODO: make the progress reporting more accurate emit logProgress(TQString(), fP->fDBIndex); if (openConduit() < 0) { addSyncLogEntry(i18n("Exiting on cancel.")); endBackup(); fActionStatus = BackupIncomplete; return; } // TODO: Is there a way to skip unchanged databases? int res = deviceLink()->getNextDatabase( fP->fDBIndex, &info ); if (res < 0) { if ( fP->fFullBackup ) { addSyncLogEntry( i18n("Full backup complete.") ); } else { addSyncLogEntry( i18n("Fast backup complete.") ); } endBackup(); fActionStatus = BackupComplete; return; } fP->addDBInfo( &info ); // see if user told us not to back this creator or database up... if (fP->allowBackup(&info)) { // back up DB if this is a full backup *or* in non-full backups, // only backup data, not applications. if ( (fP->fFullBackup) || !PilotDatabase::isResource(&info) ) { addSyncLogEntry(i18n("Backing up: %1").arg(Pilot::fromPilot(info.name))); if (!startBackupThread(&info)) { WARNINGKPILOT << "Could not create local database for <" << info.name << ">" << endl; } else { // The thread has started, so we will be woken // up by it eventually when it is done. Do *NOT* // fall through to the single-shot timer below, // because that would return us to the backup // function too soon. return; } } else { // Just skip resource DBs during an update hotsync. DEBUGKPILOT << fname << ": Skipping database <" << info.name << "> (resource database)" << endl; } } else { DEBUGKPILOT << fname << ": Skipping database <" << info.name << "> (no-backup list)" << endl; TQString s = i18n("Skipping %1") .arg(Pilot::fromPilot(info.name)); addSyncLogEntry(s); } TQTimer::singleShot(0,this,TQ_SLOT(backupOneDB())); } /** * This method will back up a single database from the Pilot to a directory on * our filesystem. If our user asks us to do a full backup, then we will unconditionally * copy the database file from the Pilot into the backup directory. Otherwise, we will * check to see if the database has any modified records in it on the pilot. If the * database has not changed on the Pilot, then there's nothing to backup and we return. * * @return @c true if the backup has started (in another thread). * You must wait on the thread to end with a User or User+1 * type event and not start another backup thread. * @return @c false if there is no backup to do. Diagnostic messages * will already have been printed. */ bool BackupAction::startBackupThread(DBInfo *info) { FUNCTIONSETUP; // now we look to see if the database on the pilot has at least one changed record // in it. we do this so that we don't waste time backing up a database that has // not changed. note: don't bother with this check if we're doing a full backup. if (!fP->fFullBackup) { // Check if this DB has modified records. PilotDatabase *serial=deviceLink()->database(info); if (!serial->isOpen()) { WARNINGKPILOT << "Unable to open database <" << info->name << ">" << endl; KPILOT_DELETE(serial); addSyncLogEntry(i18n("Backup of %1 failed.\n") .arg(Pilot::fromPilot(info->name))); return false; } int index=0; PilotRecord*rec=serial->readNextModifiedRec(&index); if (!rec) { DEBUGKPILOT << fname << ": No modified records." << endl; KPILOT_DELETE(serial); return false; } // Exists, with modified records. KPILOT_DELETE(rec); KPILOT_DELETE(serial); } // if we're here then we are going to back this database up. do some basic sanity // checks and proceed.... TQString databaseName(Pilot::fromPilot(info->name)); databaseName.replace('/', '_'); TQString fullBackupName = fP->fBackupDir + databaseName; if (PilotDatabase::isResource(info)) { fullBackupName.append(CSL1(".prc")); } else { fullBackupName.append(CSL1(".pdb")); } DEBUGKPILOT << fname << ": Backing up database to: [" << fullBackupName << "]" << endl; /* Ensure that DB-open flag is not kept */ info->flags &= ~dlpDBFlagOpen; if (fBackupThread) { WARNINGKPILOT << "Starting new backup thread before the old one is done." << endl; return false; } fBackupThread = new Thread(this,deviceLink(),fullBackupName,info); fBackupThread->start(); return true; } /* virtual */ bool BackupAction::event( TQEvent *e ) { if (e->type() == (TQEvent::Type)Thread::TerminateOK) { KPILOT_DELETE(fBackupThread); // This was a successful termination. addSyncLogEntry( i18n("... OK.\n"), false ); TQTimer::singleShot(0,this,TQ_SLOT(backupOneDB())); return true; } if (e->type() == (TQEvent::Type)Thread::TerminateFailure) { KPILOT_DELETE(fBackupThread); // Unsuccessful termination. addSyncLogEntry( i18n("Backup failed.") ); TQTimer::singleShot(0,this,TQ_SLOT(backupOneDB())); return true; } return SyncAction::event(e); } void BackupAction::endBackup() { FUNCTIONSETUP; fP->fDBIndex = (-1); fActionStatus = BackupEnded; fP->fDeviceDBs.sort(); TQString old( TQString::null ); TQStringList::Iterator itr = fP->fDeviceDBs.begin(); while ( itr != fP->fDeviceDBs.end() ) { if ( old == *itr ) { itr = fP->fDeviceDBs.remove( itr ); } else { old = *itr; ++itr; } } KPilotSettings::setDeviceDBs( fP->fDeviceDBs ); emit syncDone(this); } FileInstallAction::FileInstallAction(KPilotLink * p, const TQString & d) : SyncAction(p, "fileInstall"), fDBIndex(-1), fTimer(0L), fDir(d) { FUNCTIONSETUP; } FileInstallAction::~FileInstallAction() { FUNCTIONSETUP; KPILOT_DELETE(fTimer); } /* virtual */ bool FileInstallAction::exec() { FUNCTIONSETUP; TQDir installDir(fDir); fList = installDir.entryList(TQDir::Files | TQDir::NoSymLinks | TQDir::Readable); #ifdef DEBUG DEBUGKPILOT << fname << ": Installing " << fList.count() << " files" << endl; #endif fDBIndex = 0; emit logMessage(i18n("[File Installer]")); // Possibly no files to install? if (!fList.count()) { emit logMessage(i18n("No Files to install")); delayDone(); return true; } fTimer = new TQTimer(this); TQObject::connect(fTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(installNextFile())); fTimer->start(0, false); emit logProgress(i18n("Installing one file", "Installing %n Files",fList.count()), 0); return true; } /* slot */ void FileInstallAction::installNextFile() { FUNCTIONSETUP; Q_ASSERT(fDBIndex >= 0); Q_ASSERT((unsigned) fDBIndex <= fList.count()); #ifdef DEBUG DEBUGKPILOT << fname << ": Installing file index " << fDBIndex << " (of " << fList.count() << ")" << endl; #endif if ((!fList.count()) || ((unsigned) fDBIndex >= fList.count())) { #ifdef DEBUG DEBUGKPILOT << fname << ": Peculiar file index, bailing out." << endl; #endif KPILOT_DELETE(fTimer); fDBIndex = (-1); emit logProgress(i18n("Done Installing Files"), 100); delayDone(); return; } const TQString filePath = fDir + fList[fDBIndex]; const TQString fileName = fList[fDBIndex]; fDBIndex++; #ifdef DEBUG DEBUGKPILOT << fname << ": Installing file " << filePath << endl; #endif TQString m = i18n("Installing %1").arg(fileName); emit logProgress(m,(100 * fDBIndex) / (fList.count()+1)); m+=CSL1("\n"); emit addSyncLogEntry(m,false /* Don't print in KPilot's log. */ ); struct pi_file *f = 0L; // Check DB is ok, return false after warning user if (!resourceOK(fileName,filePath)) goto nextFile; f = pi_file_open(const_cast ((const char *) TQFile::encodeName(filePath))); #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0 if (pi_file_install(f, pilotSocket(), 0) < 0) #else if (pi_file_install(f, pilotSocket(), 0, NULL) < 0) #endif { WARNINGKPILOT << "Failed to install." << endl; emit logError(i18n("Cannot install file "%1"."). arg(fileName)); } else { TQFile::remove(filePath); } nextFile: if (f) pi_file_close(f); if (fDBIndex == -1) { fTimer->stop(); delayDone(); // emit syncDone(this); } } // Check that the given file path is a good resource // file - in particular that the resource name is ok. bool FileInstallAction::resourceOK(const TQString &fileName, const TQString &filePath) { FUNCTIONSETUP; if (!TQFile::exists(filePath)) { emit logError(i18n("Unable to open file "%1"."). arg(fileName)); return false; } struct pi_file *f = pi_file_open(const_cast ((const char *) TQFile::encodeName(filePath))); if (!f) { emit logError(i18n("Unable to open file "%1"."). arg(fileName)); return false; } struct DBInfo info; #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0 if (pi_file_get_info(f,&info) < 0) { emit logError(i18n("Unable to read file "%1"."). arg(fileName)); return false; } #else pi_file_get_info(f,&info); #endif // Looks like strlen, but we can't be sure of a NUL // termination. info.name[sizeof(info.name)-1]=0; bool r = (strlen(info.name) < 32); pi_file_close(f); if (!r) { emit logError(i18n("The database in "%1" has a " "resource name that is longer than 31 characters. " "This suggests a bug in the tool used to create the database. " "KPilot cannot install this database.").arg(fileName)); } return r; } /* virtual */ TQString FileInstallAction::statusString() const { FUNCTIONSETUP; if (fDBIndex < 0) { return TQString(CSL1("Idle")); } else { if ((unsigned) fDBIndex >= fList.count()) { return TQString(CSL1("Index out of range")); } else { return TQString(CSL1("Installing %1")).arg(fList[fDBIndex]); } } } CheckUser::CheckUser(KPilotLink * p, TQWidget * vp): SyncAction(p, vp, "userCheck") { FUNCTIONSETUP; } CheckUser::~CheckUser() { FUNCTIONSETUP; } /* virtual */ bool CheckUser::exec() { FUNCTIONSETUP; TQString guiUserName = KPilotSettings::userName(); TQString pilotUserName = fHandle->getPilotUser().name(); bool pilotUserEmpty = pilotUserName.isEmpty(); // 4 cases to handle: // guiUserName empty / not empty // pilotUserName empty / not empty // // if (guiUserName.isEmpty()) { if (pilotUserEmpty) { TQString defaultUserName = i18n("A common name", "John Doe"); TQString q = i18n("Neither KPilot nor the " "handheld have a username set. " "They should be set. " "Should KPilot set them to a default value " "(%1)?").arg(defaultUserName); if (questionYesNo(q, i18n("User Unknown") /* ,"askUserNone" */) == KMessageBox::Yes) { KPilotSettings::setUserName(defaultUserName); fHandle->getPilotUser().setName(defaultUserName); guiUserName=defaultUserName; pilotUserName=defaultUserName; } } else { TQString q = i18n("The handheld has a username set " "(%1) but KPilot does not. Should " "KPilot use this username in future?"). arg(pilotUserName); if (questionYesNo(q, i18n("User Unknown") /* ,"askUserSome" */ ) == KMessageBox::Yes) { KPilotSettings::setUserName(pilotUserName); guiUserName=pilotUserName; } } } else { if (pilotUserEmpty) { TQString q = CSL1(""); q += i18n("KPilot has a username set " "(%1) but the handheld does not. " "Should KPilot's username be set in the " "handheld as well?").arg(guiUserName); q += i18n("
(Note: If your handheld " "has been reset to factory defaults, you " "should use Restore instead of a " "regular HotSync. Click on Cancel to " "stop this sync.)"); q += CSL1("
"); int r = questionYesNoCancel(q, i18n("User Unknown")); switch (r) { case KMessageBox::Yes: DEBUGKPILOT << fname << ": Setting user name in pilot to " << guiUserName << endl; fHandle->getPilotUser().setName(guiUserName); pilotUserName=guiUserName; break; case KMessageBox::No: // Nothing to do .. continue with sync break; case KMessageBox::Cancel: default: return false; } } else { if (guiUserName != pilotUserName) { TQString q = i18n("The handheld thinks that " "the username is %1; " "however, KPilot says you are %2." "Which of these is the correct name?\n" "If you click on Cancel, the sync will proceed, " "but the usernames will not be changed."). arg(pilotUserName). arg(guiUserName); int r = questionYesNoCancel(q, i18n("User Mismatch"), TQString(), 20, i18n("Use KPilot Name"), i18n("Use Handheld Name")); switch (r) { case KMessageBox::Yes: fHandle->getPilotUser().setName(guiUserName); pilotUserName=guiUserName; break; case KMessageBox::No: KPilotSettings::setUserName(pilotUserName); guiUserName=pilotUserName; break; case KMessageBox::Cancel: default: // TODO: cancel the sync... Or just don't change any user name? break; } } } } #ifdef DEBUG DEBUGKPILOT << fname << ": User name set to pc <" << guiUserName << "> hh <" << fHandle->getPilotUser().name() << ">" << endl; #endif KPilotSettings::writeConfig(); // Now we've established which user will be used, // fix the database location for local databases. // // TQString pathName = TDEGlobal::dirs()->saveLocation("data", CSL1("kpilot/DBBackup/")); if (!guiUserName.isEmpty()) { pathName.append(guiUserName); pathName.append(CSL1("/")); } PilotLocalDatabase::setDBPath(pathName); delayDone(); return true; } class RestoreInfo { public: struct DBInfo DBInfo; TQString path; } ; class RestoreAction::Private { public: TQString fPreferRestoreDir; /**< Preference setting where to get data from. */ TQValueList fDBList; TQTimer fTimer; TQValueList::ConstIterator fDBIterator; int fDBIndex; }; RestoreAction::RestoreAction(KPilotLink * p, TQWidget * visible ) : SyncAction(p, visible, "restoreAction") { FUNCTIONSETUP; fP = new Private; } void RestoreAction::setDirectory( const TQString &path ) { fP->fPreferRestoreDir = path; } /* virtual */ bool RestoreAction::exec() { FUNCTIONSETUP; TQString dirname; if (fP->fPreferRestoreDir.isEmpty()) { dirname = PilotLocalDatabase::getDBPath(); } else { dirname = fP->fPreferRestoreDir; } #ifdef DEBUG DEBUGKPILOT << fname << ": Restoring user " << dirname << endl; #endif TQDir dir(dirname, TQString(), TQDir::Name, TQDir::Files | TQDir::Readable | TQDir::NoSymLinks); if (!dir.exists()) { WARNINGKPILOT << "Restore directory " << dirname << " does not exist." << endl; fActionStatus = Error; addSyncLogEntry(i18n("Restore directory does not exist.") + CSL1(" ") + i18n("Restore not performed.")); return false; } dirname = dir.absPath(); if (questionYesNo(i18n("Are you sure you want to completely " "restore your Pilot from the backup directory " "(%1)? This will erase any information " "you currently have on your Pilot."). arg(dirname), i18n("Restore Pilot")) != KMessageBox::Yes) { emit logError(i18n("Restore not performed.")); addSyncLogEntry(i18n("Canceled by user.") + CSL1(" ") + i18n("Restore not performed.")); // You might call this an error, but that causes // a frightening message in the log .. and the // user already _knows_ the restore didn't happen. // So instead, act as if everything was ok. delayDone(); return true; } emit logProgress(i18n("Restoring %1...").arg(TQString()),1); for (unsigned int i = 0; i < dir.count(); i++) { TQString s; RestoreInfo info; s = dirname + TQDir::separator() + dir[i]; DEBUGKPILOT << fname << ": Adding " << s << " to restore list." << endl; if ( PilotLocalDatabase::infoFromFile( s, &info.DBInfo ) ) { info.path = s; fP->fDBList.append(info); } else { WARNINGKPILOT << "Can't open " << s << endl; logMessage(i18n("File '%1' cannot be read.").arg(s)); } } fP->fDBIndex = 0; fP->fDBIterator = fP->fDBList.begin(); fActionStatus = InstallingFiles; TQObject::connect(&(fP->fTimer), TQ_SIGNAL(timeout()), this, TQ_SLOT(installNextFile())); fP->fTimer.start(0, false); return true; } /* slot */ void RestoreAction::installNextFile() { FUNCTIONSETUP; Q_ASSERT(fActionStatus == InstallingFiles); if (fP->fDBIterator == fP->fDBList.end()) { fP->fTimer.stop(); fActionStatus = Done; addSyncLogEntry(i18n("OK.")); delayDone(); return; } const RestoreInfo dbi = *(fP->fDBIterator); ++(fP->fDBIterator); ++(fP->fDBIndex); DEBUGKPILOT << fname << ": Trying to install " << dbi.path << endl; if (openConduit() < 0) { WARNINGKPILOT << "Restore apparently canceled." << endl; logMessage(i18n("Restore incomplete.")); fActionStatus = Done; emit syncDone(this); return; } TQFileInfo databaseInfo(dbi.path); addSyncLogEntry(databaseInfo.fileName()); emit logProgress(i18n("Restoring %1...").arg(databaseInfo.fileName()), (100*fP->fDBIndex) / (fP->fDBList.count()+1)) ; if ( !deviceLink()->installFiles( dbi.path, false /* don't delete */ ) ) { WARNINGKPILOT << "Couldn't restore " << dbi.path << endl; logError(i18n("Cannot restore file `%1'.") .arg(databaseInfo.fileName())); } } /* virtual */ TQString RestoreAction::statusString() const { FUNCTIONSETUP; TQString s; switch (status()) { case InstallingFiles: s.append(CSL1("Installing Files (")); s.append(TQString::number(fP->fDBIndex)); s.append(CSL1(")")); break; case GettingFileInfo: s.append(CSL1("Getting File Info (")); s.append(TQString::number(fP->fDBIndex)); s.append(CSL1(")")); break; default: return SyncAction::statusString(); } return s; } BackupAction::Thread::Thread( BackupAction *parent, KPilotLink *link, const TQString &filename, const DBInfo *info ) { fParent = parent; fLink = link; fFilename = filename; memcpy(&fDBInfo,info,sizeof(DBInfo)); } void BackupAction::Thread::run() { if (fLink->retrieveDatabase(fFilename,&fDBInfo)) { // Successful. TQApplication::postEvent( fParent, new TQEvent( (TQEvent::Type)TerminateOK ) ); } else { // Failed TQApplication::postEvent( fParent, new TQEvent( (TQEvent::Type)TerminateFailure ) ); } }