kpilot Library API Documentation

hotSync.cc

00001 /* hotSync.cc                           KPilot
00002 **
00003 ** Copyright (C) 2001 by Dan Pilone
00004 **
00005 ** This file defines SyncActions, which are used to perform some specific
00006 ** task during a HotSync. Conduits are not included here, nor are
00007 ** sync actions requiring user interaction. Those can be found in the
00008 ** conduits subdirectory or interactiveSync.h.
00009 */
00010 
00011 /*
00012 ** This program is free software; you can redistribute it and/or modify
00013 ** it under the terms of the GNU General Public License as published by
00014 ** the Free Software Foundation; either version 2 of the License, or
00015 ** (at your option) any later version.
00016 **
00017 ** This program is distributed in the hope that it will be useful,
00018 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00020 ** GNU General Public License for more details.
00021 **
00022 ** You should have received a copy of the GNU General Public License
00023 ** along with this program in a file called COPYING; if not, write to
00024 ** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00025 ** MA 02111-1307, USA.
00026 */
00027 
00028 /*
00029 ** Bug reports and questions can be sent to kde-pim@kde.org.
00030 */
00031 
00032 static const char *hotsync_id =
00033     "$Id: hotSync.cc,v 1.27.4.1 2004/03/26 22:47:02 adridg Exp $";
00034 
00035 #include "options.h"
00036 
00037 #include <time.h>
00038 #include <unistd.h>
00039 
00040 #include <pi-file.h>
00041 
00042 #include <qtimer.h>
00043 #include <qfile.h>
00044 #include <qfileinfo.h>
00045 #include <qdir.h>
00046 #include <qvaluelist.h>
00047 #include <qregexp.h>
00048 #include <qtextcodec.h>
00049 
00050 #include <kglobal.h>
00051 #include <kstandarddirs.h>
00052 #include <kapplication.h>
00053 
00054 #include "pilotUser.h"
00055 #include "pilotAppCategory.h"
00056 #include "syncStack.h"
00057 #include "pilotSerialDatabase.h"
00058 #include "pilotLocalDatabase.h"
00059 #include "pilotDatabase.h"
00060 #include "kpilotConfig.h"
00061 
00062 #include "hotSync.moc"
00063 
00064 TestLink::TestLink(KPilotDeviceLink * p) :
00065     SyncAction(p, "testLink")
00066 {
00067     FUNCTIONSETUP;
00068 
00069     (void) hotsync_id;
00070 }
00071 
00072 /* virtual */ bool TestLink::exec()
00073 {
00074     FUNCTIONSETUP;
00075 
00076     int i;
00077     int dbindex = 0;
00078     int count = 0;
00079     struct DBInfo db;
00080 
00081     addSyncLogEntry(i18n("Testing.\n"));
00082 
00083 #ifdef BRUTE_FORCE
00084     for (i=0; i<32; i++)
00085 #else
00086     while ((i = fHandle->getNextDatabase(dbindex,&db)) > 0)
00087 #endif
00088     {
00089 #ifdef BRUTE_FORCE
00090         if (fHandle->getNextDatabase(i,&db) < 1)
00091         {
00092             DEBUGKPILOT << fname << ": No database index " << i << endl;
00093             continue;
00094         }
00095 #endif
00096 
00097         count++;
00098         dbindex = db.index + 1;
00099 
00100 #ifdef DEBUG
00101         DEBUGKPILOT << fname << ": Read database " << db.name << endl;
00102 #endif
00103 
00104         // Let the Pilot User know what's happening
00105         openConduit();
00106         // Let the KDE User know what's happening
00107         // Pretty sure all database names are in latin1.
00108         emit logMessage(i18n("Syncing database %1...")
00109             .arg(QString::fromLatin1(db.name)));
00110 
00111         kapp->processEvents();
00112     }
00113 
00114     emit logMessage(i18n("HotSync finished."));
00115     emit syncDone(this);
00116     return true;
00117 }
00118 
00119 BackupAction::BackupAction(KPilotDeviceLink * p, int mode) :
00120     SyncAction(p, "backupAction"), fMode(mode), fFullBackup(mode & ActionQueue::FlagFull)
00121 {
00122     FUNCTIONSETUP;
00123 
00124     fDatabaseDir = KGlobal::dirs()->saveLocation("data",
00125         CSL1("kpilot/DBBackup/"));
00126 }
00127 
00128 /* virtual */ QString BackupAction::statusString() const
00129 {
00130     FUNCTIONSETUP;
00131     QString s(CSL1("BackupAction="));
00132 
00133     switch (status())
00134     {
00135     case Init:
00136         s.append(CSL1("Init"));
00137         break;
00138     case Error:
00139         s.append(CSL1("Error"));
00140         break;
00141     case FullBackup:
00142         s.append(CSL1("FullBackup"));
00143         break;
00144     case FastBackup:
00145         s.append(CSL1("FastBackup"));
00146         break;
00147     case BackupEnded:
00148         s.append(CSL1("BackupEnded"));
00149         break;
00150     case BackupIncomplete:
00151         s.append(CSL1("BackupIncomplete"));
00152         break;
00153     case BackupComplete:
00154         s.append(CSL1("BackupComplete"));
00155         break;
00156     default:
00157         s.append(CSL1("(unknown "));
00158         s.append(QString::number(status()));
00159         s.append(CSL1(")"));
00160     }
00161 
00162     return s;
00163 }
00164 
00165 
00166 /* virtual */ bool BackupAction::exec()
00167 {
00168     FUNCTIONSETUP;
00169 
00170 #ifdef DEBUG
00171     DEBUGDAEMON << fname
00172         << ": This Pilot user's name is \""
00173         << fHandle->getPilotUser()->getUserName() << "\"" << endl;
00174 #endif
00175 
00176     fBackupDir =
00177         fDatabaseDir +
00178         PilotAppCategory::codec()->toUnicode(fHandle->getPilotUser()->getUserName()) +
00179         CSL1("/");
00180 
00181     if (fFullBackup)
00182     {
00183         fStatus = FullBackup;
00184         addSyncLogEntry(i18n("Full backup started."));
00185     }
00186     else
00187     {
00188         fStatus = FastBackup;
00189         addSyncLogEntry(i18n("Fast backup started"));
00190     }
00191 
00192     if (!checkBackupDirectory(fBackupDir))
00193     {
00194         fStatus=BackupIncomplete;
00195         // Don't issue an error message, checkBackupDirectory
00196         // did this already...
00197         return false;
00198     }
00199 
00200     fTimer = new QTimer(this);
00201     QObject::connect(fTimer, SIGNAL(timeout()),
00202         this, SLOT(backupOneDB()));
00203 
00204     fDBIndex = 0;
00205 
00206     fTimer->start(0, false);
00207     return true;
00208 }
00209 
00210 bool BackupAction::checkBackupDirectory(QString backupDir)
00211 {
00212     FUNCTIONSETUP;
00213     QFileInfo fi(backupDir);
00214 
00215     if (!(fi.exists() && fi.isDir()))
00216     {
00217 #ifdef DEBUG
00218         DEBUGDAEMON << fname
00219             << ": Need to create backup directory for user "
00220             << fHandle->getPilotUser()->getUserName() << endl;
00221 #endif
00222 
00223         fi = QFileInfo(fDatabaseDir);
00224         if (!(fi.exists() && fi.isDir()))
00225         {
00226             kdError() << k_funcinfo
00227                 << ": Database backup directory "
00228                 << "doesn't exist."
00229                 << endl;
00230             return false;
00231         }
00232 
00233         QDir databaseDir(backupDir);
00234 
00235         if (!databaseDir.mkdir(backupDir, true))
00236         {
00237             kdError() << k_funcinfo
00238                 << ": Can't create backup directory." << endl;
00239             return false;
00240         }
00241     }
00242     return true;
00243 }
00244 
00245 
00246 /* slot */ void BackupAction::backupOneDB()
00247 {
00248     FUNCTIONSETUP;
00249 
00250     struct DBInfo info;
00251 
00252     emit logProgress(QString::null, fDBIndex);
00253 
00254     if (openConduit() < 0)
00255     {
00256 #ifdef DEBUG
00257         DEBUGDAEMON << fname
00258             << ": openConduit failed. User cancel?" << endl;
00259 #endif
00260 
00261         addSyncLogEntry(i18n("Exiting on cancel."));
00262         endBackup();
00263         fStatus = BackupIncomplete;
00264         return;
00265     }
00266 
00267     // TODO: Is there a way to skip unchanged databases?
00268     int res=fHandle->getNextDatabase(fDBIndex, &info);
00269     if (res < 0)
00270     {
00271 #ifdef DEBUG
00272         DEBUGDAEMON << fname << ": Backup complete." << endl;
00273 #endif
00274 
00275         if (fFullBackup)
00276             addSyncLogEntry(i18n("Full backup complete."));
00277         else
00278             addSyncLogEntry(i18n("Fast backup complete."));
00279         endBackup();
00280         fStatus = BackupComplete;
00281         return;
00282     }
00283 
00284     fDBIndex = info.index + 1;
00285     
00286     QStringList nobackupdb = KPilotConfig::getConfig().getNoBackupDatabases();
00287     QStringList match = nobackupdb.grep(QString::fromLatin1(info.name));
00288     if (match.isEmpty())
00289     {
00290 
00291         // Pretty sure all database names are latin1.
00292         QString s = i18n("Backing up: %1")
00293             .arg(QString::fromLatin1(info.name));
00294         addSyncLogEntry(s);
00295 
00296         if (!createLocalDatabase(&info))
00297         {
00298             kdError() << k_funcinfo
00299                 << ": Couldn't create local database for "
00300                 << info.name << endl;
00301             addSyncLogEntry(i18n("Backup of %1 failed.\n")
00302                 .arg(QString::fromLatin1(info.name)));
00303         }
00304         else
00305         {
00306             addSyncLogEntry(i18n(" .. OK\n"),false); // Not in kpilot log.
00307         }
00308     }
00309     else
00310     {
00311         QString s = CSL1("Skipping %1")
00312             .arg(QString::fromLatin1(info.name));
00313         addSyncLogEntry(s);
00314     }
00315 
00316 }
00317 
00318 bool BackupAction::createLocalDatabase(DBInfo * info)
00319 {
00320     FUNCTIONSETUP;
00321 
00322 #ifdef DEBUG
00323     DEBUGDAEMON << fname
00324         << ": Looking in directory " << fBackupDir << endl;
00325 #endif
00326 
00327     QString databaseName(QString::fromLatin1(info->name));
00328     if (!fFullBackup)
00329     {
00330         // open the serial db first so that the local db is not read into memory
00331         // in case of an error
00332         PilotSerialDatabase*serial=new PilotSerialDatabase(pilotSocket(), databaseName);
00333         if (serial->isDBOpen())
00334         {
00335             PilotLocalDatabase*local=new PilotLocalDatabase(fBackupDir, databaseName);
00336             if (local->isDBOpen())
00337             {
00338                 // Now walk through all modified records
00339                 int index=0;
00340                 PilotRecord*rec=serial->readNextModifiedRec(&index);
00341                 while (rec)
00342                 {
00343                     local->writeRecord(rec);
00344                     KPILOT_DELETE(rec);
00345                     rec=serial->readNextModifiedRec(&index);
00346                 }
00347                 KPILOT_DELETE(local);
00348                 KPILOT_DELETE(serial);
00349                 return true;
00350             }
00351             KPILOT_DELETE(local);
00352         }
00353         KPILOT_DELETE(serial);
00354 #ifdef DEBUG
00355         DEBUGCONDUIT<<"Fast backup not possible with database "<<info->name<<". Will do full backup on it"<<endl;
00356 #endif
00357     }
00358 
00359     // Either we want a full backup, or fast backup encoutered a problem
00360     // Just fetch the database to the backup dir
00361     if (!checkBackupDirectory(fBackupDir)) return false;
00362 
00363 #if QT_VERSION < 0x30100
00364     databaseName.replace(QRegExp(CSL1("/")), CSL1("_"));
00365 #else
00366     databaseName.replace('/', CSL1("_"));
00367 #endif
00368 
00369     QString fullBackupName = fBackupDir + databaseName;
00370 
00371     if (info->flags & dlpDBFlagResource)
00372     {
00373         fullBackupName.append(CSL1(".prc"));
00374     }
00375     else
00376     {
00377         fullBackupName.append(CSL1(".pdb"));
00378     }
00379 
00380 #ifdef DEBUG
00381     DEBUGDB << fname
00382         << ": Creating local database " << fullBackupName << endl;
00383 #endif
00384 
00385     /* Ensure that DB-open flag is not kept */
00386     info->flags &= ~dlpDBFlagOpen;
00387 
00388     return fHandle->retrieveDatabase(fullBackupName,info);
00389 }
00390 
00391 void BackupAction::endBackup()
00392 {
00393     FUNCTIONSETUP;
00394 
00395     KPILOT_DELETE(fTimer);
00396     fDBIndex = (-1);
00397     fStatus = BackupEnded;
00398 
00399     emit syncDone(this);
00400 }
00401 
00402 FileInstallAction::FileInstallAction(KPilotDeviceLink * p,
00403     const QString & d,
00404     const QStringList & l) :
00405     SyncAction(p, "fileInstall"),
00406     fDBIndex(-1),
00407     fTimer(0L),
00408     fDir(d),
00409     fList(l)
00410 {
00411     FUNCTIONSETUP;
00412 
00413 #ifdef DEBUG
00414     DEBUGDAEMON << fname << ": File list has "
00415         << fList.  count() << " entries" << endl;
00416 
00417     QStringList::ConstIterator i;
00418 
00419     for (i = fList.begin(); i != fList.end(); ++i)
00420     {
00421         DEBUGDAEMON << fname << ": " << *i << endl;
00422     }
00423 #endif
00424 }
00425 
00426 FileInstallAction::~FileInstallAction()
00427 {
00428     FUNCTIONSETUP;
00429 
00430     KPILOT_DELETE(fTimer);
00431 }
00432 
00433 /* virtual */ bool FileInstallAction::exec()
00434 {
00435     FUNCTIONSETUP;
00436 
00437     fDBIndex = 0;
00438 
00439 #ifdef DEBUG
00440     DEBUGDAEMON << fname
00441         << ": Installing " << fList.count() << " files" << endl;
00442 #endif
00443 
00444     emit logMessage(i18n("[File Installer]"));
00445 
00446     // Possibly no files to install?
00447     if (!fList.count())
00448     {
00449         emit logMessage(i18n("No Files to install"));
00450         return delayDone();
00451     }
00452 
00453     fTimer = new QTimer(this);
00454     QObject::connect(fTimer, SIGNAL(timeout()),
00455         this, SLOT(installNextFile()));
00456 
00457     fTimer->start(0, false);
00458 
00459     emit logProgress(i18n("Installing one file",
00460         "Installing %n Files",fList.count()), 0);
00461     return true;
00462 }
00463 
00464 /* slot */ void FileInstallAction::installNextFile()
00465 {
00466     FUNCTIONSETUP;
00467 
00468     Q_ASSERT(fDBIndex >= 0);
00469     Q_ASSERT((unsigned) fDBIndex <= fList.count());
00470 
00471 #ifdef DEBUG
00472     DEBUGDAEMON << fname
00473         << ": Installing file index "
00474         << fDBIndex << " (of " << fList.count() << ")" << endl;
00475 #endif
00476 
00477     if ((!fList.count()) || ((unsigned) fDBIndex >= fList.count()))
00478     {
00479 #ifdef DEBUG
00480         DEBUGDAEMON << fname
00481             << ": Peculiar file index, bailing out." << endl;
00482 #endif
00483         KPILOT_DELETE(fTimer);
00484         fDBIndex = (-1);
00485         emit logProgress(i18n("Done Installing Files"), 100);
00486         emit syncDone(this);
00487         return;
00488     }
00489 
00490     const QString filePath = fDir + fList[fDBIndex];
00491     const QString fileName = fList[fDBIndex];
00492 
00493     fDBIndex++;
00494 
00495 #ifdef DEBUG
00496     DEBUGDAEMON << fname << ": Installing file " << filePath << endl;
00497 #endif
00498 
00499     QString m = i18n("Installing %1").arg(fileName);
00500     emit logProgress(m,(100 * fDBIndex) / (fList.count()+1));
00501     m+=QString::fromLatin1("\n");
00502     emit addSyncLogEntry(m,true /* Don't print in KPilot's log. */ );
00503 
00504 
00505     struct pi_file *f = 0L;
00506 
00507     f = pi_file_open(const_cast <char *>
00508         ((const char *) QFile::encodeName(filePath)));
00509 
00510     if (!f)
00511     {
00512         kdWarning() << k_funcinfo
00513             << ": Unable to open file." << endl;
00514 
00515         emit logError(i18n("Unable to open file &quot;%1&quot;!").
00516             arg(fileName));
00517         goto nextFile;
00518     }
00519 
00520     if (pi_file_install(f, pilotSocket(), 0) < 0)
00521     {
00522         kdWarning() << k_funcinfo << ": failed to install." << endl;
00523 
00524 
00525         emit logError(i18n("Cannot install file &quot;%1&quot;!").
00526             arg(fileName));
00527     }
00528     else
00529     {
00530         QFile::remove(filePath);
00531     }
00532 
00533 
00534 nextFile:
00535     if (f) pi_file_close(f);
00536     if (fDBIndex == -1)
00537     {
00538         emit syncDone(this);
00539     }
00540 }
00541 
00542 /* virtual */ QString FileInstallAction::statusString() const
00543 {
00544     FUNCTIONSETUP;
00545     if (fDBIndex < 0)
00546     {
00547         return QString(CSL1("Idle"));
00548     }
00549     else
00550     {
00551         if ((unsigned) fDBIndex >= fList.count())
00552         {
00553             return QString(CSL1("Index out of range"));
00554         }
00555         else
00556         {
00557             return QString(CSL1("Installing %1")).arg(fList[fDBIndex]);
00558         }
00559     }
00560 }
00561 
00562 CleanupAction::CleanupAction(KPilotDeviceLink *p)  : SyncAction(p,"cleanupAction")
00563 {
00564     FUNCTIONSETUP;
00565 }
00566 
00567 CleanupAction::~CleanupAction()
00568 {
00569 #ifdef DEBUG
00570     FUNCTIONSETUP;
00571     DEBUGDAEMON << fname
00572         << ": Deleting @" << (int)this << endl;
00573 #endif
00574 }
00575 
00576 /* virtual */ bool CleanupAction::exec()
00577 {
00578     FUNCTIONSETUP;
00579 
00580     fHandle->finishSync();
00581     emit syncDone(this);
00582     return true;
00583 }
00584 
00585 
KDE Logo
This file is part of the documentation for kpilot Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:36:47 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003