summaryrefslogtreecommitdiffstats
path: root/kpilot/hotSync.cc
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-02-16 20:17:18 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-02-16 20:17:18 +0000
commitcb7eddb91455a69cf66fcd717e91a51ca5e2cfef (patch)
treecf5546e4d7c44370fbe9ca2be937bd254f30ebaa /kpilot/hotSync.cc
downloadkpilot-cb7eddb91455a69cf66fcd717e91a51ca5e2cfef.tar.gz
kpilot-cb7eddb91455a69cf66fcd717e91a51ca5e2cfef.zip
Moved kpilot from kdepim to applications, as the core Trinity libraries should not contain hardware-dependent software
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kpilot@1221127 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kpilot/hotSync.cc')
-rw-r--r--kpilot/hotSync.cc1156
1 files changed, 1156 insertions, 0 deletions
diff --git a/kpilot/hotSync.cc b/kpilot/hotSync.cc
new file mode 100644
index 0000000..e0bc7e3
--- /dev/null
+++ b/kpilot/hotSync.cc
@@ -0,0 +1,1156 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
+** Copyright (C) 2006 Adriaan de Groot <groot@kde.org>
+**
+** 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 <time.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <pi-file.h>
+#include <pi-util.h>
+
+#include <tqtimer.h>
+#include <tqfile.h>
+#include <tqfileinfo.h>
+#include <tqdir.h>
+#include <tqvaluelist.h>
+#include <tqregexp.h>
+#include <tqstringlist.h>
+#include <tqthread.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+
+#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 QThread
+{
+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<unsigned long> 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::tqfromLatin1( buff );
+
+ TQString dbname = Pilot::fromPilot( info->name, 32 );
+
+ if ( !fDeviceDBs.tqcontains( creator ) )
+ {
+ fDeviceDBs << creator;
+ }
+ if ( !fDeviceDBs.tqcontains( 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<unsigned long> &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<unsigned long>::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;
+
+ KStandardDirs::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 =
+ KGlobal::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,TQT_SLOT(backupOneDB()));
+ return true;
+}
+
+/* slot */ void BackupAction::backupOneDB()
+{
+ FUNCTIONSETUP;
+
+ struct DBInfo info;
+
+ // TODO: make the progress reporting more accurate
+ emit logProgress(TQString::null, 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,TQT_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.tqreplace('/', '_');
+
+ 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,TQT_SLOT(backupOneDB()));
+ return true;
+ }
+ if (e->type() == (TQEvent::Type)Thread::TerminateFailure)
+ {
+ KPILOT_DELETE(fBackupThread);
+ // Unsuccessful termination.
+ addSyncLogEntry( i18n("Backup failed.") );
+ TQTimer::singleShot(0,this,TQT_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, TQT_SIGNAL(timeout()),
+ this, TQT_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 <char *>
+ ((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 &quot;%1&quot;.").
+ 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 &quot;%1&quot;.").
+ arg(fileName));
+ return false;
+ }
+
+ struct pi_file *f = pi_file_open(const_cast <char *>
+ ((const char *) TQFile::encodeName(filePath)));
+
+ if (!f)
+ {
+ emit logError(i18n("Unable to open file &quot;%1&quot;.").
+ 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 &quot;%1&quot;.").
+ 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 &quot;%1&quot; 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("<qt>Neither KPilot nor the "
+ "handheld have a username set. "
+ "They <i>should</i> be set. "
+ "Should KPilot set them to a default value "
+ "(<i>%1</i>)?</qt>").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("<qt>The handheld has a username set "
+ "(<i>%1</i>) but KPilot does not. Should "
+ "KPilot use this username in future?</qt>").
+ arg(pilotUserName);
+
+ if (questionYesNo(q, i18n("User Unknown") /* ,"askUserSome" */ ) ==
+ KMessageBox::Yes)
+ {
+ KPilotSettings::setUserName(pilotUserName);
+ guiUserName=pilotUserName;
+ }
+ }
+ }
+ else
+ {
+ if (pilotUserEmpty)
+ {
+ TQString q = CSL1("<qt>");
+ q += i18n("KPilot has a username set "
+ "(<i>%1</i>) but the handheld does not. "
+ "Should KPilot's username be set in the "
+ "handheld as well?").arg(guiUserName);
+ q += i18n("<br/>(<i>Note:</i> If your handheld "
+ "has been reset to factory defaults, you "
+ "should use <i>Restore</i> instead of a "
+ "regular HotSync. Click on Cancel to "
+ "stop this sync.)");
+ q += CSL1("</qt>");
+
+ 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("<qt>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.</qt>").
+ arg(pilotUserName).
+ arg(guiUserName);
+
+ int r = questionYesNoCancel(q,
+ i18n("User Mismatch"),
+ TQString::null,
+ 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 = KGlobal::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<RestoreInfo> fDBList;
+ TQTimer fTimer;
+ TQValueList<RestoreInfo>::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::null, 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("<qt>Are you sure you want to completely "
+ "restore your Pilot from the backup directory "
+ "(<i>%1</i>)? This will erase any information "
+ "you currently have on your Pilot.</qt>").
+ arg(dirname),
+ i18n("Restore Pilot")) != KMessageBox::Yes)
+ {
+ emit logError(i18n("Restore <i>not</i> 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::null),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), TQT_SIGNAL(timeout()),
+ this, TQT_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 ) );
+ }
+}
+
+