kpilot/kpilot

interactiveSync.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 specializes SyncAction to a kind that can have interaction
00007 ** with the user without the Sync timing out.
00008 */
00009 
00010 /*
00011 ** This program is free software; you can redistribute it and/or modify
00012 ** it under the terms of the GNU General Public License as published by
00013 ** the Free Software Foundation; either version 2 of the License, or
00014 ** (at your option) any later version.
00015 **
00016 ** This program is distributed in the hope that it will be useful,
00017 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 ** GNU General Public License for more details.
00020 **
00021 ** You should have received a copy of the GNU General Public License
00022 ** along with this program in a file called COPYING; if not, write to
00023 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00024 ** MA 02110-1301, USA.
00025 */
00026 
00027 /*
00028 ** Bug reports and questions can be sent to kde-pim@kde.org.
00029 */
00030 
00031 static const char *interactivesync_id =
00032     "$Id: interactiveSync.cc 437980 2005-07-23 19:53:57Z kainhofe $";
00033 
00034 #include "options.h"
00035 
00036 #include <time.h>
00037 #include <unistd.h>
00038 #include <stdio.h>
00039 
00040 #include <pi-socket.h>
00041 #include <pi-file.h>
00042 
00043 #include <qtimer.h>
00044 #include <qvbox.h>
00045 #include <qlayout.h>
00046 #include <qlabel.h>
00047 #include <qmessagebox.h>
00048 #include <qdir.h>
00049 #include <qfile.h>
00050 #include <qfileinfo.h>
00051 #include <qtl.h>
00052 #include <qstyle.h>
00053 #include <qtextcodec.h>
00054 
00055 #include <kdialogbase.h>
00056 #include <kglobal.h>
00057 #include <kstandarddirs.h>
00058 #include <kmessagebox.h>
00059 
00060 #include <kapplication.h>
00061 
00062 #include "pilotUser.h"
00063 #include "pilotAppCategory.h"
00064 #include "pilotLocalDatabase.h"
00065 #include "kpilotConfig.h"
00066 #include "kpilotlink.h"
00067 
00068 #include "interactiveSync.moc"
00069 
00070 
00071 CheckUser::CheckUser(KPilotDeviceLink * p, QWidget * vp):
00072     SyncAction(p, vp, "userCheck")
00073 {
00074     FUNCTIONSETUP;
00075 
00076     (void) interactivesync_id;
00077 }
00078 
00079 CheckUser::~CheckUser()
00080 {
00081     FUNCTIONSETUP;
00082 }
00083 
00084 /* virtual */ bool CheckUser::exec()
00085 {
00086     FUNCTIONSETUP;
00087 
00088     QString guiUserName = KPilotSettings::userName();
00089     QString pilotUserName = PilotAppCategory::codec()->
00090         toUnicode(fHandle->getPilotUser()->getUserName());
00091     bool pilotUserEmpty = pilotUserName.isEmpty();
00092     // 4 cases to handle:
00093     //    guiUserName empty / not empty
00094     //    pilotUserName empty / not empty
00095     //
00096     //
00097     if (guiUserName.isEmpty())
00098     {
00099         if (pilotUserEmpty)
00100         {
00101             QString defaultUserName =
00102                 i18n("A common name", "John Doe");
00103 
00104             QString q = i18n("<qt>Neither KPilot nor the "
00105                 "handheld have a username set. "
00106                 "They <i>should</i> be set. "
00107                 "Should KPilot set them to a default value "
00108                 "(<i>%1</i>)?</qt>").arg(defaultUserName);
00109 
00110             if (questionYesNo(q, i18n("User Unknown") /* ,"askUserNone" */) ==
00111                 KMessageBox::Yes)
00112             {
00113                 KPilotSettings::setUserName(defaultUserName);
00114                 fHandle->getPilotUser()->
00115                     setUserName(PilotAppCategory::codec()->fromUnicode(defaultUserName));
00116                 guiUserName=defaultUserName;
00117                 pilotUserName=defaultUserName;
00118             }
00119 
00120         }
00121         else
00122         {
00123             QString q = i18n("<qt>The handheld has a username set "
00124                 "(<i>%1</i>) but KPilot does not. Should "
00125                 "KPilot use this username in future?").
00126                 arg(pilotUserName);
00127 
00128             if (questionYesNo(q, i18n("User Unknown") /* ,"askUserSome" */ ) ==
00129                 KMessageBox::Yes)
00130             {
00131                 KPilotSettings::setUserName(pilotUserName);
00132                 guiUserName=pilotUserName;
00133             }
00134         }
00135     }
00136     else
00137     {
00138         if (pilotUserEmpty)
00139         {
00140             QString q = i18n("<qt>KPilot has a username set "
00141                 "(<i>%1</i>) but the handheld does not. "
00142                 "Should KPilot's username be set in the "
00143                 "handheld as well?").arg(guiUserName);
00144 
00145             if (questionYesNo(q, i18n("User Unknown") /* ,"askUserSome" */) ==
00146                 KMessageBox::Yes)
00147             {
00148 #ifdef DEBUG
00149                 DEBUGDAEMON << fname
00150                     << ": Setting user name in pilot to "
00151                     << guiUserName << endl;
00152 #endif
00153 
00154                 QCString l1 = PilotAppCategory::codec()->fromUnicode(guiUserName);
00155 
00156                 fHandle->getPilotUser()->setUserName(l1.data());
00157                 pilotUserName=guiUserName;
00158             }
00159         }
00160         else
00161         {
00162             if (guiUserName != pilotUserName)
00163             {
00164                 QString q = i18n("<qt>The handheld thinks that "
00165                     "the username is %1; "
00166                     "however, KPilot says you are %2."
00167                     "Which of these is the correct name?\n"
00168                     "If you click on Cancel, the sync will proceed, "
00169                     "but the usernames will not be changed.").
00170                     arg(pilotUserName).
00171                     arg(guiUserName);
00172 
00173                 int r = questionYesNoCancel(q,
00174                     i18n("User Mismatch"),
00175                     QString::null,
00176                     20,
00177                     i18n("Use KPilot Name"),
00178                     i18n("Use Handheld Name"));
00179                 switch (r)
00180                 {
00181                 case KMessageBox::Yes:
00182                     fHandle->getPilotUser()->setUserName(
00183                         PilotAppCategory::codec()->fromUnicode(guiUserName));
00184                     pilotUserName=guiUserName;
00185                     break;
00186                 case KMessageBox::No:
00187                     KPilotSettings::setUserName(pilotUserName);
00188                     guiUserName=pilotUserName;
00189                     break;
00190                 case KMessageBox::Cancel:
00191                 default:
00192                     // TODO: cancel the sync... Or just don't change any user name?
00193                     break;
00194                 }
00195             }
00196         }
00197     }
00198 
00199 
00200 #ifdef DEBUG
00201     DEBUGCONDUIT << fname
00202         << ": User name set to gui<"
00203         << guiUserName
00204         << "> hh<"
00205         << fHandle->getPilotUser()->getUserName() << ">" << endl;
00206 #endif
00207 
00208     KPilotSettings::writeConfig();
00209 
00210     // Now we've established which user will be used,
00211     // fix the database location for local databases.
00212     //
00213     //
00214     QString pathName = KGlobal::dirs()->saveLocation("data",
00215         CSL1("kpilot/DBBackup/"));
00216     if (!guiUserName.isEmpty())
00217     {
00218         pathName.append(guiUserName);
00219         pathName.append(CSL1("/"));
00220     }
00221     PilotLocalDatabase::setDBPath(pathName);
00222 
00223     emit syncDone(this);
00224     return true;
00225 }
00226 
00227 class RestoreInfo
00228 {
00229 public:
00230     struct db DBInfo;
00231     QString path;
00232 } ;
00233 
00234 class RestoreAction::RestoreActionPrivate
00235 {
00236 public:
00237     QString fDatabaseDir;
00238     QValueList<RestoreInfo *> fDBList;
00239     QTimer fTimer;
00240     QValueList<RestoreInfo *>::ConstIterator fDBIterator;
00241     int fDBIndex;
00242 };
00243 
00244 
00245 RestoreAction::RestoreAction(KPilotDeviceLink * p, QWidget * visible ) :
00246     SyncAction(p, visible, "restoreAction")
00247 {
00248     FUNCTIONSETUP;
00249 
00250     fP = new RestoreActionPrivate;
00251     fP->fDatabaseDir = KGlobal::dirs()->saveLocation("data",
00252         CSL1("kpilot/DBBackup/"));
00253 }
00254 
00255 /* virtual */ bool RestoreAction::exec()
00256 {
00257     FUNCTIONSETUP;
00258 
00259 #ifdef DEBUG
00260     DEBUGDAEMON << fname
00261         << ": Restoring from base directory "
00262         << *(PilotLocalDatabase::getDBPath()) << endl;
00263 #endif
00264 
00265     QString dirname = *(PilotLocalDatabase::getDBPath());
00266 
00267 #ifdef DEBUG
00268     DEBUGDAEMON << fname << ": Restoring user " << dirname << endl;
00269 #endif
00270 
00271     if (questionYesNo(i18n("<qt>Are you sure you want to completely "
00272                 "restore your Pilot from the backup directory "
00273                 "(<i>%1</i>)? This will erase any information "
00274                 "you currently have on your Pilot.</qt>").
00275             arg(dirname),
00276             i18n("Restore Pilot")) != KMessageBox::Yes)
00277     {
00278         emit logError(i18n("Restore <i>not</i> performed."));
00279 
00280         addSyncLogEntry(i18n("Canceled by user.") + CSL1(" ") +
00281             i18n("Restore not performed."));
00282         emit syncDone(this);
00283 
00284         return true;
00285     }
00286 
00287     QDir dir(dirname, QString::null, QDir::Name,
00288         QDir::Files | QDir::Readable | QDir::NoSymLinks);
00289 
00290     if (!dir.exists())
00291     {
00292         kdWarning() << k_funcinfo
00293             << ": Restore directory "
00294             << dirname << " does not exist." << endl;
00295         fActionStatus = Error;
00296         addSyncLogEntry(i18n("Restore directory does not exist.") +
00297             CSL1(" ") + i18n("Restore not performed."));
00298         return false;
00299     }
00300 
00301     emit logProgress(i18n("Restoring %1...").arg(QString::null),1);
00302 
00303     for (unsigned int i = 0; i < dir.count(); i++)
00304     {
00305         QString s;
00306         RestoreInfo *dbi;
00307         struct DBInfo info;
00308         struct pi_file *f;
00309 
00310         s = dir[i];
00311 
00312 #ifdef DEBUG
00313         DEBUGDAEMON << fname
00314             << ": Adding " << s << " to restore list." << endl;
00315 #endif
00316 
00317     char * fileName = qstrdup( QFile::encodeName(dirname + s) );
00318     f = pi_file_open( fileName );
00319     delete fileName;
00320         if (!f)
00321         {
00322             kdWarning() << k_funcinfo
00323                 << ": Can't open " << s << endl;
00324             logMessage(i18n("File '%1' cannot be read.").arg(s));
00325             continue;
00326         }
00327 
00328 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
00329         if (!pi_file_get_info(f, &info))
00330 #else
00331         pi_file_get_info(f,&info);
00332         if (true)
00333 #endif
00334         {
00335             dbi = new RestoreInfo;
00336             memcpy(&dbi->DBInfo,&info,sizeof(struct DBInfo));
00337             dbi->path = dirname + s;
00338             fP->fDBList.append(dbi);
00339         }
00340         else
00341         {
00342             kdWarning() << k_funcinfo
00343                 << ": Can't open " << s << endl;
00344             logMessage(i18n("File '%1' cannot be read.").arg(s));
00345         }
00346 
00347         pi_file_close(f);
00348         f = 0L;
00349     }
00350 
00351     fP->fDBIndex = 0;
00352     fP->fDBIterator = fP->fDBList.begin();
00353     fActionStatus = GettingFileInfo;
00354 
00355     QObject::connect(&(fP->fTimer), SIGNAL(timeout()),
00356         this, SLOT(getNextFileInfo()));
00357 
00358     fP->fTimer.start(0, false);
00359     return true;
00360 }
00361 
00362 /* slot */ void RestoreAction::getNextFileInfo()
00363 {
00364     FUNCTIONSETUP;
00365 
00366     Q_ASSERT(fActionStatus == GettingFileInfo);
00367 
00368     QObject::disconnect(&(fP->fTimer), SIGNAL(timeout()),
00369         this, SLOT(getNextFileInfo()));
00370     fP->fTimer.stop();
00371 
00372     qBubbleSort(fP->fDBList);
00373 
00374     fP->fDBIndex = 0;
00375     fP->fDBIterator = fP->fDBList.begin();
00376     fActionStatus = InstallingFiles;
00377 
00378     QObject::connect(&(fP->fTimer), SIGNAL(timeout()),
00379         this, SLOT(installNextFile()));
00380     fP->fTimer.start(0, false);
00381 }
00382 
00383 /* slot */ void RestoreAction::installNextFile()
00384 {
00385     FUNCTIONSETUP;
00386 
00387     Q_ASSERT(fActionStatus == InstallingFiles);
00388 
00389     const RestoreInfo *dbi = 0L;
00390 
00391     if (fP->fDBIterator == fP->fDBList.end())
00392     {
00393         QObject::disconnect(&(fP->fTimer), SIGNAL(timeout()),
00394             this, SLOT(getNextFileInfo()));
00395         fP->fTimer.stop();
00396 
00397         fActionStatus = Done;
00398         addSyncLogEntry(i18n("OK."));
00399         delayDone();
00400         return;
00401     }
00402 
00403     dbi = *fP->fDBIterator;
00404     ++(fP->fDBIterator);
00405     ++(fP->fDBIndex);
00406 #ifdef DEBUG
00407     DEBUGDAEMON << fname << ": Trying to install " << dbi->path << endl;
00408 #endif
00409 
00410     if (openConduit() < 0)
00411     {
00412         kdWarning() << k_funcinfo
00413             << ": Restore apparently canceled." << endl;
00414         logMessage(i18n("Restore incomplete."));
00415         fActionStatus = Done;
00416         emit syncDone(this);
00417 
00418         return;
00419     }
00420 
00421     QFileInfo databaseInfo(dbi->path);
00422     addSyncLogEntry(databaseInfo.fileName());
00423     emit logProgress(i18n("Restoring %1...").arg(databaseInfo.fileName()),
00424         (100*fP->fDBIndex) / (fP->fDBList.count()+1)) ;
00425 
00426     char * fileName = qstrdup( dbi->path.utf8() );
00427     pi_file *f  = pi_file_open( fileName );
00428     delete fileName;
00429 
00430     if (!f)
00431     {
00432         kdWarning() << k_funcinfo
00433             << ": Can't open "
00434             << dbi->path << " for restore." << endl;
00435         logError(i18n("Cannot open file `%1' for restore.")
00436             .arg(databaseInfo.fileName()));
00437         return;
00438     }
00439 
00440 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
00441     if (pi_file_install(f, pilotSocket(), 0) < 0)
00442 #else
00443     if (pi_file_install(f, pilotSocket(), 0, NULL) < 0)
00444 #endif
00445     {
00446         kdWarning() << k_funcinfo
00447             << ": Couldn't  restore " << dbi->path << endl;
00448         logError(i18n("Cannot restore file `%1'.")
00449             .arg(databaseInfo.fileName()));
00450     }
00451 
00452     pi_file_close(f);
00453 }
00454 
00455 /* virtual */ QString RestoreAction::statusString() const
00456 {
00457     FUNCTIONSETUP;
00458     QString s;
00459 
00460     switch (status())
00461     {
00462     case InstallingFiles:
00463         s.append(CSL1("Installing Files ("));
00464         s.append(QString::number(fP->fDBIndex));
00465         s.append(CSL1(")"));
00466         break;
00467     case GettingFileInfo:
00468         s.append(CSL1("Getting File Info ("));
00469         s.append(QString::number(fP->fDBIndex));
00470         s.append(CSL1(")"));
00471         break;
00472     default:
00473         return SyncAction::statusString();
00474     }
00475 
00476     return s;
00477 }
00478 
00479 
KDE Home | KDE Accessibility Home | Description of Access Keys