kpilot/kpilot

pilotDaemon.cc

00001 /* KPilot
00002 **
00003 ** Copyright (C) 1998-2001 by Dan Pilone
00004 ** Copyright (C) 2001-2004 by Adriaan de Groot
00005 ** Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 **
00007 ** This is the KPilot Daemon, which does the actual communication with
00008 ** the Pilot and with the conduits.
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., 51 Franklin Street, Fifth Floor, Boston,
00025 ** MA 02110-1301, USA.
00026 */
00027 
00028 /*
00029 ** Bug reports and questions can be sent to kde-pim@kde.org
00030 */
00031 
00032 #include "options.h"
00033 
00034 #include <stdlib.h>
00035 
00036 #include <qtimer.h>
00037 #include <qtooltip.h>
00038 #include <qpixmap.h>
00039 
00040 #include <kuniqueapplication.h>
00041 #include <kaboutapplication.h>
00042 #include <kcmdlineargs.h>
00043 #include <kwin.h>
00044 #include <kurl.h>
00045 #include <kpopupmenu.h>
00046 #include <kiconloader.h>
00047 #include <kdebug.h>
00048 #include <kprocess.h>
00049 #include <dcopclient.h>
00050 #include <kurldrag.h>
00051 #include <kservice.h>
00052 #include <kapplication.h>
00053 #include <khelpmenu.h>
00054 
00055 #include "pilotRecord.h"
00056 
00057 #include "fileInstaller.h"
00058 #include "pilotUser.h"
00059 #include "pilotDatabase.h"
00060 #include "kpilotlink.h"
00061 #include "kpilotdevicelink.h"
00062 
00063 #include "hotSync.h"
00064 #include "interactiveSync.h"
00065 #include "syncStack.h"
00066 #include "internalEditorAction.h"
00067 #include "logFile.h"
00068 
00069 #include "kpilotConfig.h"
00070 
00071 
00072 #include "kpilotDCOP_stub.h"
00073 #include "kpilotDCOP.h"
00074 #include "loggerDCOP_stub.h"
00075 
00076 #include "pilotDaemon.moc"
00077 
00078 static KAboutData *aboutData = 0L;
00079 
00080 PilotDaemonTray::PilotDaemonTray(PilotDaemon * p) :
00081     KSystemTray(0, "pilotDaemon"),
00082     fSyncTypeMenu(0L),
00083     daemon(p),
00084     kap(0L),
00085     fBlinkTimer(0L)
00086 {
00087     FUNCTIONSETUP;
00088     setupWidget();
00089     setAcceptDrops(true);
00090 }
00091 
00092 /* virtual */ void PilotDaemonTray::dragEnterEvent(QDragEnterEvent * e)
00093 {
00094     FUNCTIONSETUP;
00095     e->accept(KURLDrag::canDecode(e));
00096 }
00097 
00098 /* virtual */ void PilotDaemonTray::dropEvent(QDropEvent * e)
00099 {
00100     FUNCTIONSETUP;
00101 
00102     KURL::List list;
00103 
00104     KURLDrag::decode(e, list);
00105 
00106     QStringList files;
00107     for(KURL::List::ConstIterator it = list.begin(); it != list.end(); ++it)
00108     {
00109        if ((*it).isLocalFile())
00110           files << (*it).path();
00111     }
00112 
00113     daemon->addInstallFiles(files);
00114 }
00115 
00116 /* virtual */ void PilotDaemonTray::mousePressEvent(QMouseEvent * e)
00117 {
00118     FUNCTIONSETUP;
00119 
00120     switch (e->button())
00121     {
00122         case RightButton:
00123             {
00124                 KPopupMenu *menu = contextMenu();
00125                 contextMenuAboutToShow(menu);
00126                 menu->popup(e->globalPos());
00127             }
00128             break;
00129         case LeftButton:
00130             if (daemon) daemon->slotRunKPilot();
00131             break;
00132         default:
00133             KSystemTray::mousePressEvent(e);
00134     }
00135 }
00136 
00137 /* virtual */ void PilotDaemonTray::closeEvent(QCloseEvent *)
00138 {
00139     FUNCTIONSETUP;
00140     daemon->quitNow();
00141 }
00142 
00143 void PilotDaemonTray::setupWidget()
00144 {
00145     FUNCTIONSETUP;
00146 
00147     KGlobal::iconLoader()->addAppDir( CSL1("kpilot") );
00148     icons[Normal] = loadIcon( CSL1("kpilotDaemon") );
00149     icons[Busy] = loadIcon( CSL1("busysync") );
00150     icons[NotListening] = loadIcon( CSL1("nosync") );
00151 
00152     slotShowNotListening();
00153     QTimer::singleShot(2000,this,SLOT(slotShowNormal()));
00154 
00155     KPopupMenu *menu = contextMenu();
00156 
00157     menuKPilotItem = menu->insertItem(i18n("Start &KPilot"), daemon,
00158         SLOT(slotRunKPilot()));
00159     menuConfigureConduitsItem = menu->insertItem(i18n("&Configure KPilot..."),
00160         daemon, SLOT(slotRunConfig()));
00161     menu->insertSeparator();
00162 
00163     fSyncTypeMenu = new KPopupMenu(menu,"sync_type_menu");
00164     QString once = i18n("Appended to names of sync types to indicate the sync will happen just one time"," (once)");
00165 #define MI(a) fSyncTypeMenu->insertItem( \
00166         SyncAction::SyncMode::name(SyncAction::SyncMode::a) + once, \
00167         (int)(SyncAction::SyncMode::a));
00168     fSyncTypeMenu->insertItem(i18n("Default (%1)")
00169         .arg(SyncAction::SyncMode::name((SyncAction::SyncMode::Mode)KPilotSettings::syncType())),
00170         0);
00171     fSyncTypeMenu->insertSeparator();
00172 
00173         // Keep this synchronized with kpilotui.rc and kpilot.cc if at all possible.
00174     MI(eHotSync);
00175     MI(eFullSync);
00176     MI(eBackup);
00177     MI(eRestore);
00178     MI(eCopyHHToPC);
00179     MI(eCopyPCToHH);
00180 
00181     fSyncTypeMenu->setCheckable(true);
00182     fSyncTypeMenu->setItemChecked(0,true);
00183 #undef MI
00184     connect(fSyncTypeMenu,SIGNAL(activated(int)),daemon,SLOT(requestSync(int)));
00185     menu->insertItem(i18n("Next &Sync"),fSyncTypeMenu);
00186 
00187     KHelpMenu *help = new KHelpMenu(menu,aboutData);
00188     menu->insertItem(
00189         KGlobal::iconLoader()->loadIconSet(CSL1("help"),KIcon::Small,0,true),
00190         i18n("&Help"),help->menu(),false /* no whatsthis */);
00191 
00192 
00193 
00194 #ifdef DEBUG
00195     DEBUGKPILOT << fname << ": Finished getting icons" << endl;
00196 #endif
00197 }
00198 
00199 void PilotDaemonTray::slotShowAbout()
00200 {
00201     FUNCTIONSETUP;
00202 
00203     if (!kap)
00204     {
00205         kap = new KAboutApplication(0, "kpdab", false);
00206     }
00207 
00208     kap->show();
00209 }
00210 
00211 
00212 void PilotDaemonTray::enableRunKPilot(bool b)
00213 {
00214     FUNCTIONSETUP;
00215     contextMenu()->setItemEnabled(menuKPilotItem, b);
00216     contextMenu()->setItemEnabled(menuConfigureConduitsItem, b);
00217 }
00218 
00219 
00220 void PilotDaemonTray::changeIcon(IconShape i)
00221 {
00222     FUNCTIONSETUP;
00223     if (icons[i].isNull())
00224     {
00225         kdWarning() << k_funcinfo
00226             << ": Icon #"<<i<<" is NULL!" << endl;
00227     }
00228     setPixmap(icons[i]);
00229     fCurrentIcon = i;
00230 }
00231 
00232 void PilotDaemonTray::slotShowNormal()
00233 {
00234     FUNCTIONSETUP;
00235     changeIcon(Normal);
00236 }
00237 
00238 void PilotDaemonTray::slotShowBusy()
00239 {
00240     FUNCTIONSETUP;
00241     changeIcon(Busy);
00242 }
00243 
00244 void PilotDaemonTray::slotShowNotListening()
00245 {
00246     FUNCTIONSETUP;
00247     changeIcon( NotListening );
00248 }
00249 
00250 void PilotDaemonTray::slotBusyTimer()
00251 {
00252     if (fCurrentIcon == Busy) changeIcon(Normal);
00253     else if (fCurrentIcon == Normal) changeIcon(Busy);
00254 }
00255 
00256 void PilotDaemonTray::startHotSync()
00257 {
00258     changeIcon(Busy);
00259     if (!fBlinkTimer)
00260     {
00261         fBlinkTimer = new QTimer(this,"blink timer");
00262     }
00263     if (fBlinkTimer)
00264     {
00265         connect(fBlinkTimer,SIGNAL(timeout()),
00266             this,SLOT(slotBusyTimer()));
00267         fBlinkTimer->start(350,false);
00268     }
00269 }
00270 
00271 void PilotDaemonTray::endHotSync()
00272 {
00273     changeIcon(Normal);
00274     if (fBlinkTimer)
00275     {
00276         fBlinkTimer->stop();
00277     }
00278 }
00279 
00280 
00281 PilotDaemon::PilotDaemon() :
00282     DCOPObject("KPilotDaemonIface"),
00283     fDaemonStatus(INIT),
00284     fPostSyncAction(None),
00285     fPilotLink(0L),
00286     fNextSyncType(SyncAction::SyncMode::eHotSync,true),
00287     fSyncStack(0L),
00288     fTray(0L),
00289     fInstaller(0L),
00290     fLogFile(0L),
00291     fLogStub(new LoggerDCOP_stub("kpilot", "LogIface")),
00292     fLogFileStub(new LoggerDCOP_stub("kpilotDaemon", "LogIface")),
00293     fKPilotStub(new KPilotDCOP_stub("kpilot", "KPilotIface")),
00294     fTempDevice(QString::null)
00295 {
00296     FUNCTIONSETUP;
00297 
00298     setupPilotLink();
00299     reloadSettings();
00300 
00301     if (fDaemonStatus == ERROR)
00302     {
00303         kdWarning() << k_funcinfo
00304             << ": Connecting to device failed." << endl;
00305         return;
00306     }
00307 
00308     fInstaller = new FileInstaller;
00309     fLogFile = new LogFile;
00310     connect(fInstaller, SIGNAL(filesChanged()),
00311         this, SLOT(slotFilesChanged()));
00312 
00313     fNextSyncType.setMode( KPilotSettings::syncType() );
00314 
00315 #ifdef DEBUG
00316     DEBUGKPILOT << fname
00317         << ": The daemon is ready with status "
00318         << statusString() << " (" << (int) fDaemonStatus << ")" << endl;
00319 #endif
00320 }
00321 
00322 PilotDaemon::~PilotDaemon()
00323 {
00324     FUNCTIONSETUP;
00325 
00326     KPILOT_DELETE(fPilotLink);
00327     KPILOT_DELETE(fSyncStack);
00328     KPILOT_DELETE(fInstaller);
00329 
00330     (void) PilotDatabase::instanceCount();
00331 }
00332 
00333 void PilotDaemon::addInstallFiles(const QStringList &l)
00334 {
00335     FUNCTIONSETUP;
00336 
00337     fInstaller->addFiles( l, fTray );
00338 }
00339 
00340 int PilotDaemon::getPilotSpeed()
00341 {
00342     FUNCTIONSETUP;
00343 
00344     int speed = KPilotSettings::pilotSpeed();
00345 
00346     // Translate the speed entry in the
00347     // config file to something we can
00348     // put in the environment (for who?)
00349     //
00350     //
00351     const char *speedname = 0L;
00352 
00353     switch (speed)
00354     {
00355     case 0:
00356         speedname = "PILOTRATE=9600";
00357         break;
00358     case 1:
00359         speedname = "PILOTRATE=19200";
00360         break;
00361     case 2:
00362         speedname = "PILOTRATE=38400";
00363         break;
00364     case 3:
00365         speedname = "PILOTRATE=57600";
00366         break;
00367     case 4:
00368         speedname = "PILOTRATE=115200";
00369         break;
00370     default:
00371         speedname = "PILOTRATE=9600";
00372     }
00373 
00374 #ifdef DEBUG
00375     DEBUGKPILOT << fname
00376         << ": Speed set to "
00377         << speedname << " (" << speed << ")" << endl;
00378 #endif
00379 
00380     putenv((char *) speedname);
00381 
00382     return speed;
00383 }
00384 
00385 
00386 void PilotDaemon::showTray()
00387 {
00388     FUNCTIONSETUP;
00389 
00390     if (!fTray)
00391     {
00392 #ifdef DEBUG
00393         DEBUGKPILOT << fname << ": No tray icon to display!" << endl;
00394 #endif
00395 
00396         return;
00397     }
00398 
00399     // Copied from Klipper
00400     KWin::setSystemTrayWindowFor(fTray->winId(), 0);
00401     fTray->setGeometry(-100, -100, 42, 42);
00402     fTray->show();
00403 
00404 #ifdef DEBUG
00405     DEBUGKPILOT << fname << ": Tray icon displayed." << endl;
00406 #endif
00407 
00408     updateTrayStatus();
00409 }
00410 
00411 /* DCOP ASYNC */ void PilotDaemon::setTempDevice(QString d)
00412 {
00413     if ( !d.isEmpty() ){
00414         fTempDevice = d;
00415         if (fPilotLink)
00416             fPilotLink->setTempDevice( fTempDevice );
00417         reloadSettings();
00418     }
00419 }
00420 
00421 /* DCOP ASYNC */ void PilotDaemon::reloadSettings()
00422 {
00423     FUNCTIONSETUP;
00424 
00425     switch (fDaemonStatus)
00426     {
00427     case INIT:
00428     case HOTSYNC_END:
00429     case ERROR:
00430     case READY:
00431     case NOT_LISTENING:
00432         // It's OK to reload settings in these states.
00433         break;
00434     case HOTSYNC_START:
00435     case FILE_INSTALL_REQ:
00436         // Postpone the reload till the sync finishes.
00437         fPostSyncAction |= ReloadSettings;
00438         return;
00439         break;
00440     }
00441 
00442     // TODO: Is this bunch of calls really necessary to reload the settings???
00443     delete KPilotSettings::self();
00444     KPilotSettings::self()->config()->reparseConfiguration();
00445     KPilotSettings::self()->readConfig();
00446     getPilotSpeed();
00447 
00448     (void) Pilot::setupPilotCodec(KPilotSettings::encoding());
00449 
00450 #ifdef DEBUG
00451     DEBUGKPILOT << fname
00452         << ": Got configuration "
00453         << KPilotSettings::pilotDevice()
00454         << endl;
00455     DEBUGKPILOT << fname
00456         << ": Got conduit list "
00457         << (KPilotSettings::installedConduits().join(CSL1(",")))
00458         << endl;
00459 #endif
00460 
00461     requestSync(0);
00462 
00463 
00464     if (fPilotLink)
00465     {
00466 #ifdef DEBUG
00467         DEBUGKPILOT << fname
00468             << ": Resetting with device "
00469             << KPilotSettings::pilotDevice()
00470             << endl;
00471 #endif
00472 
00473         fPilotLink->reset( KPilotSettings::pilotDevice() );
00474 #ifdef DEBUG
00475         DEBUGKPILOT << fname
00476             << ": Using workarounds "
00477             << KPilotSettings::workarounds()
00478             << endl;
00479 #endif
00480         if ( KPilotSettings::workarounds() == KPilotSettings::eWorkaroundUSB )
00481         {
00482 #ifdef DEBUG
00483             DEBUGKPILOT << fname
00484                 << ": Using Zire31 USB workaround." << endl;
00485 #endif
00486             fPilotLink->setWorkarounds(true);
00487         }
00488     }
00489 
00490     if (KPilotSettings::dockDaemon())
00491     {
00492         if (!fTray)
00493         {
00494             fTray = new PilotDaemonTray(this);
00495             fTray->show();
00496         }
00497         else
00498         {
00499             fTray->show();
00500         }
00501     }
00502     else
00503     {
00504         if (fTray)
00505         {
00506             fTray->hide();
00507             delete fTray;
00508 
00509             fTray = 0L;
00510         }
00511     }
00512 
00513     updateTrayStatus();
00514     logProgress(QString::null,0);
00515 }
00516 
00517 /* DCOP */ void PilotDaemon::stopListening()
00518 {
00519     fIsListening=false;
00520     fTray->changeIcon(PilotDaemonTray::NotListening);
00521     fDaemonStatus=NOT_LISTENING;
00522     fPilotLink->close();
00523 }
00524 
00525 /* DCOP */ void PilotDaemon::startListening()
00526 {
00527     fIsListening=true;
00528     fTray->changeIcon(PilotDaemonTray::Normal);
00529     fDaemonStatus=INIT;
00530     fPilotLink->reset();
00531 }
00532 
00533 /* DCOP */ QString PilotDaemon::statusString()
00534 {
00535     FUNCTIONSETUP;
00536 
00537     QString s = CSL1("PilotDaemon=");
00538     s.append(shortStatusString());
00539 
00540     s.append(CSL1("; NextSync="));
00541     s.append(fNextSyncType.name());
00542 
00543     s.append(CSL1(" ("));
00544     if (fPilotLink)
00545     {
00546         s.append(fPilotLink->statusString());
00547     }
00548     s.append(CSL1(");"));
00549 
00550     return s;
00551 }
00552 
00553 /* DCOP */ QString PilotDaemon::shortStatusString()
00554 {
00555     FUNCTIONSETUP;
00556 
00557     QString s;
00558 
00559     switch (status())
00560     {
00561     case INIT:
00562         s.append(CSL1("Waiting for sync"));
00563         break;
00564     case READY:
00565         s.append(CSL1("Listening on device"));
00566         break;
00567     case ERROR:
00568         s=CSL1("Error");
00569         break;
00570     case FILE_INSTALL_REQ:
00571         s=CSL1("Installing File");
00572         break;
00573     case HOTSYNC_END:
00574         s=CSL1("End of Hotsync");
00575         break;
00576     case HOTSYNC_START:
00577         s=CSL1("Syncing");
00578         break;
00579     case NOT_LISTENING:
00580         s.append(CSL1("Not Listening (stopped manually)"));
00581         break;
00582     }
00583 
00584     return s;
00585 }
00586 
00587 
00588 
00589 bool PilotDaemon::setupPilotLink()
00590 {
00591     FUNCTIONSETUP;
00592 
00593     KPILOT_DELETE(fPilotLink);
00594     fPilotLink = new KPilotDeviceLink( 0, 0, fTempDevice );
00595     if (!fPilotLink)
00596     {
00597         kdWarning() << k_funcinfo
00598             << ": Can't get pilot link." << endl;
00599         return false;
00600     }
00601 
00602     QObject::connect(fPilotLink, SIGNAL(deviceReady(KPilotLink*)),
00603         this, SLOT(startHotSync(KPilotLink*)));
00604     // connect the signals emitted by the pilotDeviceLink
00605     QObject::connect(fPilotLink, SIGNAL(logError(const QString &)),
00606         this, SLOT(logError(const QString &)));
00607     QObject::connect(fPilotLink, SIGNAL(logMessage(const QString &)),
00608         this, SLOT(logMessage(const QString &)));
00609     QObject::connect(fPilotLink,
00610         SIGNAL(logProgress(const QString &,int)),
00611         this, SLOT(logProgress(const QString &,int)));
00612 
00613 
00614     return true;
00615 }
00616 
00617 
00618 /* DCOP ASYNC */ void PilotDaemon::quitNow()
00619 {
00620     FUNCTIONSETUP;
00621     // Using switch to make sure we cover all the cases.
00622     //
00623     //
00624     switch (fDaemonStatus)
00625     {
00626     case INIT:
00627     case HOTSYNC_END:
00628     case ERROR:
00629     case NOT_LISTENING:
00630         getKPilot().daemonStatus(KPilotDCOP::DaemonQuit);
00631         kapp->quit();
00632         break;
00633     case READY:
00634     case HOTSYNC_START:
00635     case FILE_INSTALL_REQ:
00636         fPostSyncAction |= Quit;
00637         break;
00638     }
00639     emitDCOPSignal( "kpilotDaemonStatusChanged()", QByteArray() );
00640 }
00641 
00642 /* DCOP ASYNC */ void PilotDaemon::requestRegularSyncNext()
00643 {
00644     requestSync(SyncAction::SyncMode::eHotSync);
00645 }
00646 
00647 
00648 /* DCOP ASYNC */ void PilotDaemon::requestSync(int mode)
00649 {
00650     FUNCTIONSETUP;
00651 
00652     if ( 0==mode )
00653     {
00654         mode = KPilotSettings::syncType();
00655     }
00656 
00657     if ( !fNextSyncType.setMode(mode) )
00658     {
00659         kdWarning() << k_funcinfo << ": Ignored fake sync type " << mode << endl;
00660         return;
00661     }
00662 
00663     updateTrayStatus();
00664 
00665     if (fTray && (fTray->fSyncTypeMenu))
00666     {
00667         for (int i=((int)SyncAction::SyncMode::eHotSync);
00668             i<=((int)SyncAction::SyncMode::eRestore) /* Restore */ ;
00669             ++i)
00670         {
00671             fTray->fSyncTypeMenu->setItemChecked(i,mode==i);
00672         }
00673     }
00674 
00675     getLogger().logMessage(i18n("Next HotSync will be: %1. ").arg(fNextSyncType.name()) +
00676         i18n("Please press the HotSync button."));
00677 }
00678 
00679 /* DCOP ASYNC */ void PilotDaemon::requestSyncType(QString s)
00680 {
00681     FUNCTIONSETUP;
00682 
00683     // This checks unique prefixes of the names of the various sync types.
00684     if (s.startsWith(CSL1("H"))) requestSync(SyncAction::SyncMode::eHotSync);
00685     else if (s.startsWith(CSL1("Fu"))) requestSync(SyncAction::SyncMode::eFullSync);
00686     else if (s.startsWith(CSL1("B"))) requestSync(SyncAction::SyncMode::eBackup);
00687     else if (s.startsWith(CSL1("R"))) requestSync(SyncAction::SyncMode::eRestore);
00688     else if (s.startsWith(CSL1("T"))) { fNextSyncType.setOptions(true,false); }
00689     else if (s.startsWith(CSL1("CopyHHToPC"))) requestSync(SyncAction::SyncMode::eCopyHHToPC);
00690     else if (s.startsWith(CSL1("CopyPCToHH"))) requestSync(SyncAction::SyncMode::eCopyPCToHH);
00691     else if (s.startsWith(CSL1("D"))) requestSync(0);
00692     else
00693     {
00694         kdWarning() << ": Unknown sync type " << ( s.isEmpty() ? CSL1("<none>") : s )
00695             << endl;
00696     }
00697 }
00698 
00699 /* DCOP ASYNC */ void PilotDaemon::requestSyncOptions(bool test, bool local)
00700 {
00701     if ( !fNextSyncType.setOptions(test,local) )
00702     {
00703         kdWarning() << k_funcinfo << ": Nonsensical request for "
00704             << (test ? "test" : "notest")
00705             << ' '
00706             << (local ? "local" : "nolocal")
00707             << " in mode "
00708             << fNextSyncType.name() << endl;
00709     }
00710 }
00711 
00712 /* DCOP */ int PilotDaemon::nextSyncType() const
00713 {
00714     return fNextSyncType.mode();
00715 }
00716 
00720 QDateTime PilotDaemon::lastSyncDate()
00721 {
00722     return KPilotSettings::lastSyncTime();
00723 }
00724 
00725 
00726 static QDict<QString> *conduitNameMap = 0L;
00727 
00728 static void fillConduitNameMap()
00729 {
00730     if ( !conduitNameMap )
00731     {
00732         conduitNameMap = new QDict<QString>;
00733         conduitNameMap->setAutoDelete(true);
00734     }
00735     conduitNameMap->clear();
00736 
00737     QStringList l = KPilotSettings::installedConduits();
00738     // Fill with internal settings.
00739     if ( l.find( CSL1("internal_fileinstall") ) != l.end() ) {
00740         conduitNameMap->insert( CSL1("internal_fileinstall"),
00741                                 new QString(i18n("File Installer")) );
00742     }
00743 
00744     QStringList::ConstIterator end = l.end();
00745     for (QStringList::ConstIterator i = l.begin(); i != end; ++i)
00746     {
00747         if (!conduitNameMap->find(*i))
00748         {
00749             QString readableName = CSL1("<unknown>");
00750             KSharedPtr < KService > o = KService::serviceByDesktopName(*i);
00751             if (!o)
00752             {
00753                 kdWarning() << k_funcinfo << ": No service for " << *i << endl;
00754             }
00755             else
00756             {
00757                 readableName = o->name();
00758             }
00759             conduitNameMap->insert( *i, new QString(readableName) );
00760         }
00761     }
00762 }
00763 
00764 
00765 QStringList PilotDaemon::configuredConduitList()
00766 {
00767     fillConduitNameMap();
00768 
00769     QStringList keys;
00770 
00771     QDictIterator<QString> it(*conduitNameMap);
00772     for ( ; *it; ++it)
00773     {
00774         keys << it.currentKey();
00775     }
00776     keys.sort();
00777 
00778     QStringList::ConstIterator end = keys.end();
00779     QStringList result;
00780     for (QStringList::ConstIterator i = keys.begin(); i != end; ++i)
00781     {
00782         result << *(conduitNameMap->find(*i));
00783     }
00784 
00785     return result;
00786 }
00787 
00788 QString PilotDaemon::logFileName()
00789 {
00790     return KPilotSettings::logFileName();
00791 }
00792 
00793 QString PilotDaemon::userName()
00794 {
00795     return KPilotSettings::userName();
00796 }
00797 QString PilotDaemon::pilotDevice()
00798 {
00799     return KPilotSettings::pilotDevice();
00800 }
00801 
00802 bool PilotDaemon::killDaemonOnExit()
00803 {
00804     return KPilotSettings::killDaemonAtExit();
00805 }
00806 
00807 typedef enum { NotLocked=0, Locked=1, DCOPError=2 } KDesktopLockStatus;
00808 static KDesktopLockStatus isKDesktopLockRunning()
00809 {
00810     if (!KPilotSettings::screenlockSecure()) return NotLocked;
00811 
00812     DCOPClient *dcopptr = KApplication::kApplication()->dcopClient();
00813 
00814     // Can't tell, very weird, err on the side of safety.
00815     if (!dcopptr || !dcopptr->isAttached())
00816     {
00817         kdWarning() << k_funcinfo << ": Could not make DCOP connection. "
00818             << "Assuming screensaver is active." << endl;
00819         return DCOPError;
00820     }
00821 
00822     QByteArray data,returnValue;
00823     QCString returnType;
00824 
00825     if (!dcopptr->call("kdesktop","KScreensaverIface","isBlanked()",
00826         data,returnType,returnValue,true))
00827     {
00828         kdWarning() << k_funcinfo << ": Check for screensaver failed."
00829             << "Assuming screensaver is active." << endl;
00830         // Err on the side of safety again.
00831         return DCOPError;
00832     }
00833 
00834     if (returnType == "bool")
00835     {
00836         bool b;
00837         QDataStream reply(returnValue,IO_ReadOnly);
00838         reply >> b;
00839         return (b ? Locked : NotLocked);
00840     }
00841     else
00842     {
00843         kdWarning() << k_funcinfo << ": Strange return value from screensaver. "
00844             << "Assuming screensaver is active." << endl;
00845         // Err on the side of safety.
00846         return DCOPError;
00847     }
00848 }
00849 
00850 
00851 static void informOthers(KPilotDCOP_stub &kpilot,
00852     LoggerDCOP_stub &log,
00853     LoggerDCOP_stub &filelog)
00854 {
00855     kpilot.daemonStatus(KPilotDCOP::StartOfHotSync);
00856     log.logStartSync();
00857     filelog.logStartSync();
00858 }
00859 
00860 static bool isSyncPossible(ActionQueue *fSyncStack,
00861     KPilotLink *pilotLink,
00862     KPilotDCOP_stub &kpilot)
00863 {
00864     FUNCTIONSETUP;
00865 
00872     int kpilotstatus = kpilot.kpilotStatus();
00873     DCOPStub::Status callstatus = kpilot.status();
00874 
00875 #ifdef DEBUG
00876     if (callstatus != DCOPStub::CallSucceeded)
00877     {
00878         DEBUGKPILOT << fname <<
00879             ": Could not call KPilot for status." << endl;
00880     }
00881     else
00882     {
00883         DEBUGKPILOT << fname << ": KPilot status " << kpilotstatus << endl;
00884     }
00885 #endif
00886 
00890     if ((callstatus == DCOPStub::CallSucceeded) &&
00891         (kpilotstatus != KPilotDCOP::WaitingForDaemon))
00892     {
00893         kdWarning() << k_funcinfo <<
00894             ": KPilot returned status " << kpilotstatus << endl;
00895 
00896         fSyncStack->queueInit();
00897         fSyncStack->addAction(new SorryAction(pilotLink));
00898         return false;
00899     }
00900 
00901     switch (isKDesktopLockRunning())
00902     {
00903     case NotLocked :
00904         break; /* Fall through to return true below */
00905     case Locked :
00906         fSyncStack->queueInit();
00907         fSyncStack->addAction(new SorryAction(pilotLink,
00908             i18n("HotSync is disabled while the screen is locked.")));
00909         return false;
00910     case DCOPError :
00911         fSyncStack->queueInit();
00912         fSyncStack->addAction(new SorryAction(pilotLink,
00913             i18n("HotSync is disabled because KPilot could not "
00914             "determine the state of the screen saver. You "
00915             "can disable this security feature by unchecking "
00916             "the 'do not sync when screensaver is active' box "
00917             "in the HotSync page of the configuration dialog.")));
00918         return false;
00919     }
00920 
00921     return true;
00922 }
00923 
00924 static void queueInstaller(ActionQueue *fSyncStack,
00925     FileInstaller *fInstaller,
00926     const QStringList &c)
00927 {
00928     if (c.findIndex(CSL1("internal_fileinstall")) >= 0)
00929     {
00930         fSyncStack->queueInstaller(fInstaller->dir());
00931     }
00932 }
00933 
00934 static void queueEditors(ActionQueue *fSyncStack, KPilotLink *pilotLink)
00935 {
00936     if (KPilotSettings::internalEditors())
00937     {
00938         fSyncStack->addAction(new InternalEditorAction(pilotLink));
00939     }
00940 }
00941 
00942 static void queueConduits(ActionQueue *fSyncStack,
00943     const QStringList &conduits,
00944     SyncAction::SyncMode e)
00945 {
00946     if (conduits.count() > 0)
00947     {
00948         fSyncStack->queueConduits( conduits,e);
00949         // QString s = i18n("Conduit flags: ");
00950         // s.append(ConduitProxy::flagsForMode(e).join(CSL1(" ")));
00951         // logMessage(s);
00952     }
00953 }
00954 
00955 bool PilotDaemon::shouldBackup()
00956 {
00957 
00958     FUNCTIONSETUP;
00959 
00960     bool ret = false;
00961     int backupfreq = KPilotSettings::backupFrequency();
00962 
00963 #ifdef DEBUG
00964     DEBUGKPILOT << fname << ": Backup Frequency is: [" << backupfreq <<
00965     "]. " << endl;
00966 #endif
00967 
00968     if ( (fNextSyncType == SyncAction::SyncMode::eHotSync) ||
00969         (fNextSyncType == SyncAction::SyncMode::eFullSync) )
00970     {
00974         if ( backupfreq == SyncAction::eOnRequestOnly )
00975         {
00976 #ifdef DEBUG
00977     DEBUGKPILOT << fname << ": Should not do backup..." << endl;
00978 #endif
00979             ret = false;
00980         }
00981         else if ( backupfreq == SyncAction::eEveryHotSync )
00982         {
00983 #ifdef DEBUG
00984     DEBUGKPILOT << fname << ": Should do backup..." << endl;
00985 #endif
00986             ret = true;
00987         }
00988     }
00989 
00990     return ret;
00991 
00992 }
00993 
00994 
00995 /* slot */ void PilotDaemon::startHotSync(KPilotLink *pilotLink)
00996 {
00997     FUNCTIONSETUP;
00998 
00999     bool pcchanged=false; // If last PC to sync was a different one (implies full sync, normally)
01000     QStringList conduits ; // list of conduits to run
01001     QString s; // a generic string for stuff
01002 
01003 #ifdef DEBUG
01004     DEBUGKPILOT << fname
01005         << ": Starting Sync with type "
01006         << fNextSyncType.name() << endl;
01007     DEBUGKPILOT << fname << ": Status is " << shortStatusString() << endl;
01008     (void) PilotDatabase::instanceCount();
01009 #endif
01010 
01011     fDaemonStatus = HOTSYNC_START ;
01012     if (fTray)
01013     {
01014         fTray->startHotSync();
01015     }
01016     informOthers(getKPilot(),getLogger(),getFileLogger());
01017 
01018 
01019     // Queue to add all the actions for this sync to.
01020     fSyncStack = new ActionQueue(pilotLink);
01021 
01022     // Check if the sync is possible at all.
01023     if (!isSyncPossible(fSyncStack,pilotLink,getKPilot()))
01024     {
01025         // Sync is not possible now, sorry action was added to
01026         // the queue, and we run that -- skipping all the rest of the sync stuff.
01027         goto launch;
01028     }
01029 
01030     // Except when the user has requested a Restore, in which case she knows she doesn't
01031     // want to sync with a blank palm and then back up the result over her stored backup files,
01032     // do a Full Sync when changing the PC or using a different Palm Desktop app.
01033     if (fNextSyncType.mode() != SyncAction::SyncMode::eRestore)
01034     { // Use gethostid to determine , since JPilot uses 1+(2000000000.0*random()/(RAND_MAX+1.0))
01035         // as PC_ID, so using JPilot and KPilot is the same as using two different PCs
01036         KPilotUser &usr = pilotLink->getPilotUser();
01037         pcchanged = usr.getLastSyncPC() !=(unsigned long) gethostid();
01038 
01039         if (pcchanged)
01040         {
01041 #ifdef DEBUG
01042             DEBUGKPILOT << fname << ": PC changed. Last sync PC: [" << usr.getLastSyncPC()
01043                 << "], me: [" << (unsigned long) gethostid() << "]" << endl;
01044 #endif
01045             if ( KPilotSettings::fullSyncOnPCChange() )
01046             {
01047 #ifdef DEBUG
01048                 DEBUGKPILOT << fname << ": Setting sync mode to full sync. " << endl;
01049 #endif
01050                 fNextSyncType = SyncAction::SyncMode::eFullSync;
01051             }
01052             else
01053             {
01054 #ifdef DEBUG
01055                 DEBUGKPILOT << fname << ": Not changing sync mode because of settings. " << endl;
01056 #endif
01057             }
01058         }
01059     }
01060 
01061     // Normal case: regular sync.
01062     fSyncStack->queueInit( ActionQueue::queueCheckUser );
01063 
01064     conduits = KPilotSettings::installedConduits() ;
01065 
01066     if (fNextSyncType.isTest())
01067     {
01068         fSyncStack->addAction(new TestLink(pilotLink));
01069     }
01070     else
01071     {
01072         switch (fNextSyncType.mode())
01073         {
01074         case SyncAction::SyncMode::eBackup:
01075             if (KPilotSettings::runConduitsWithBackup() && (conduits.count() > 0))
01076             {
01077                 queueConduits(fSyncStack,conduits,fNextSyncType);
01078             }
01079             fSyncStack->addAction(new BackupAction(pilotLink,true));
01080             break;
01081         case SyncAction::SyncMode::eRestore:
01082             fSyncStack->addAction(new RestoreAction(pilotLink));
01083             queueInstaller(fSyncStack,fInstaller,conduits);
01084             break;
01085         case SyncAction::SyncMode::eFullSync:
01086         case SyncAction::SyncMode::eHotSync:
01087             // first install the files, and only then do the conduits
01088             // (conduits might want to sync a database that will be installed
01089             queueInstaller(fSyncStack,fInstaller,conduits);
01090             queueEditors(fSyncStack,pilotLink);
01091             queueConduits(fSyncStack,conduits,fNextSyncType);
01092             // After running the conduits, install new databases
01093             queueInstaller(fSyncStack,fInstaller,conduits);
01094             // And sync the remaining databases if needed.
01095             if (shouldBackup())
01096             {
01097                 fSyncStack->addAction(new BackupAction(pilotLink, (fNextSyncType == SyncAction::SyncMode::eFullSync)));
01098             }
01099             break;
01100         case SyncAction::SyncMode::eCopyPCToHH:
01101             queueConduits(fSyncStack,conduits,SyncAction::SyncMode::eCopyPCToHH);
01102             break;
01103         case SyncAction::SyncMode::eCopyHHToPC:
01104             queueConduits(fSyncStack,conduits,SyncAction::SyncMode::eCopyHHToPC);
01105             break;
01106         }
01107     }
01108 
01109 // Jump here to finalize the connections to the sync action
01110 // queue and start the actual sync.
01111 launch:
01112     fSyncStack->queueCleanup();
01113 
01114     QObject::connect(fSyncStack, SIGNAL(logError(const QString &)),
01115         this, SLOT(logError(const QString &)));
01116     QObject::connect(fSyncStack, SIGNAL(logMessage(const QString &)),
01117         this, SLOT(logMessage(const QString &)));
01118     QObject::connect(fSyncStack,
01119         SIGNAL(logProgress(const QString &,int)),
01120         this, SLOT(logProgress(const QString &,int)));
01121 
01122     QObject::connect(fSyncStack, SIGNAL(syncDone(SyncAction *)),
01123         this, SLOT(endHotSync()));
01124 
01125     QTimer::singleShot(0,fSyncStack,SLOT(execConduit()));
01126 
01127     updateTrayStatus();
01128 }
01129 
01130 /* slot */ void PilotDaemon::logMessage(const QString & s)
01131 {
01132     FUNCTIONSETUPL(2);
01133 
01134     getLogger().logMessage(s);
01135     getFileLogger().logMessage(s);
01136     updateTrayStatus(s);
01137 }
01138 
01139 /* slot */ void PilotDaemon::logError(const QString & s)
01140 {
01141     FUNCTIONSETUP;
01142 
01143     getLogger().logError(s);
01144     getFileLogger().logError(s);
01145     updateTrayStatus(s);
01146 }
01147 
01148 /* slot */ void PilotDaemon::logProgress(const QString & s, int i)
01149 {
01150     FUNCTIONSETUPL(2);
01151 
01152     getLogger().logProgress(s, i);
01153     getFileLogger().logProgress(s, i);
01154     if (!s.isEmpty()) updateTrayStatus(s);
01155 }
01156 
01157 /* slot */ void PilotDaemon::endHotSync()
01158 {
01159     FUNCTIONSETUP;
01160 
01161     if (fTray)
01162     {
01163         fTray->endHotSync();
01164     }
01165 
01166     KPILOT_DELETE(fSyncStack);
01167     fPilotLink->close();
01168 
01169     getLogger().logProgress(i18n("HotSync Completed.<br>"), 100);
01170     getFileLogger().logProgress(i18n("HotSync Completed.<br>"), 100);
01171     getLogger().logEndSync();
01172     getFileLogger().logEndSync();
01173     getKPilot().daemonStatus(KPilotDCOP::EndOfHotSync);
01174     KPilotSettings::setLastSyncTime(QDateTime::currentDateTime());
01175     KPilotSettings::self()->writeConfig();
01176 
01177     fDaemonStatus = HOTSYNC_END;
01178 
01179     if (fPostSyncAction & Quit)
01180     {
01181         getKPilot().daemonStatus(KPilotDCOP::DaemonQuit);
01182         kapp->quit();
01183     }
01184     if (fPostSyncAction & ReloadSettings)
01185     {
01186         reloadSettings();
01187     }
01188     else
01189     {
01190         QTimer::singleShot(10000,fPilotLink,SLOT(reset()));
01191     }
01192 
01193     fPostSyncAction = None;
01194     requestSync(0);
01195 
01196     (void) PilotDatabase::instanceCount();
01197 
01198     updateTrayStatus();
01199 }
01200 
01201 
01202 void PilotDaemon::slotFilesChanged()
01203 {
01204     FUNCTIONSETUP;
01205 }
01206 
01207 void PilotDaemon::slotRunKPilot()
01208 {
01209     FUNCTIONSETUP;
01210 
01211     QString kpilotError;
01212     QCString kpilotDCOP;
01213     int kpilotPID;
01214 
01215     if (KApplication::startServiceByDesktopName(CSL1("kpilot"),
01216             QString::null, &kpilotError, &kpilotDCOP, &kpilotPID
01217 #if (KDE_VERSION >= 220)
01218             // Startup notification added in 2.2
01219             , ""
01220 #endif
01221         ))
01222     {
01223         kdWarning() << k_funcinfo
01224             << ": Couldn't start KPilot! " << kpilotError << endl;
01225     }
01226     else
01227     {
01228 #ifdef DEBUG
01229         DEBUGKPILOT << fname
01230             << ": Started KPilot with DCOP name "
01231             << kpilotDCOP << " (pid " << kpilotPID << ")" << endl;
01232 #endif
01233     }
01234 }
01235 
01236 void PilotDaemon::slotRunConfig()
01237 {
01238     FUNCTIONSETUP;
01239 
01240     // This function tries to send the raise() DCOP call to kpilot.
01241     // If it succeeds, we can assume kpilot is running and then try
01242     // to send the configure() DCOP call.
01243     // If it fails (probably because kpilot isn't running) it tries
01244     // to call kpilot via KProcess (using a command line switch to
01245     // only bring up the configure dialog).
01246     //
01247     // Implementing the function this way catches all cases.
01248     // ie 1 KPilot running with configure dialog open (raise())
01249     //    2 KPilot running with dialog NOT open (configureConduits())
01250     //    3 KPilot NOT running (KProcess)
01251 
01252     DCOPClient *client = kapp->dcopClient();
01253 
01254     // This DCOP call to kpilot's raise function solves the final case
01255     // ie when kpilot already has the dialog open
01256 
01257     if ( client->isApplicationRegistered( "kpilot" ) )
01258     {
01259         client->send("kpilot", "kpilot-mainwindow#1", "raise()",QString::null);
01260         client->send("kpilot", "KPilotIface", "configure()", QString::null);
01261     }
01262     else
01263     {
01264         // KPilot not running
01265         KProcess *p = new KProcess;
01266         *p << "kpilot" << "-s";
01267 
01268         p->start();
01269     }
01270 }
01271 
01272 void PilotDaemon::updateTrayStatus(const QString &s)
01273 {
01274     if (!fTray) return;
01275 
01276     QString tipText = CSL1("<qt>");
01277     tipText.append( s );
01278     tipText.append( CSL1(" ") );
01279     tipText.append( i18n("Next sync is %1.")
01280         .arg( fNextSyncType.name() ) );
01281     tipText.append( CSL1("</qt>") );
01282 
01283     QToolTip::remove(fTray);
01284     QToolTip::add(fTray,tipText);
01285     emitDCOPSignal( "kpilotDaemonStatusChanged()", QByteArray() );
01286     // emit the same dcop signal but including the information needed by Kontact to update its kpilot summary widget
01287     QByteArray data;
01288     QDataStream arg(data, IO_WriteOnly);
01289     arg << lastSyncDate();
01290     arg << shortStatusString();
01291     arg << configuredConduitList();
01292     arg << logFileName();
01293     arg << userName();
01294     arg << pilotDevice();
01295     arg << killDaemonOnExit();
01296     emitDCOPSignal( "kpilotDaemonStatusDetails(QDateTime,QString,QStringList,QString,QString,QString,bool)", data );
01297 }
01298 
01299 static KCmdLineOptions daemonoptions[] = {
01300 #ifdef DEBUG
01301     {"debug <level>", I18N_NOOP("Set debugging level"), "0"},
01302 #endif
01303     { "device <device>", I18N_NOOP("Device to try first"), ""},
01304     {"fail-silently", /* TODO_I18N */ ("Exit instead of complaining "
01305         "about bad configuration files"), 0},
01306     KCmdLineLastOption
01307 } ;
01308 
01309 
01310 int main(int argc, char **argv)
01311 {
01312     FUNCTIONSETUP;
01313 
01314     KLocale::setMainCatalogue("kpilot");
01315 
01316     KAboutData about("kpilotDaemon",
01317         I18N_NOOP("KPilot Daemon"),
01318         KPILOT_VERSION,
01319         "KPilot - HotSync software for KDE\n\n",
01320         KAboutData::License_GPL,
01321         "(c) 1998-2000,2001, Dan Pilone (c) 2000-2004, Adriaan de Groot",
01322         0L,
01323         "http://www.kpilot.org/"
01324         );
01325     about.addAuthor("Dan Pilone",
01326         I18N_NOOP("Project Leader"),
01327         "pilone@slac.com");
01328     about.addAuthor("Adriaan de Groot",
01329         I18N_NOOP("Maintainer"),
01330         "groot@kde.org", "http://www.kpilot.org/");
01331     about.addAuthor("Reinhold Kainhofer",
01332         I18N_NOOP("Developer"),
01333         "reinhold@kainhofer.com", "http://reinhold.kainhofer.com/Linux/");
01334     aboutData = &about;
01335 
01336 
01337     KCmdLineArgs::init(argc, argv, &about);
01338     KCmdLineArgs::addCmdLineOptions(daemonoptions,"kpilotconfig");
01339     KUniqueApplication::addCmdLineOptions();
01340     KCmdLineArgs *p = KCmdLineArgs::parsedArgs();
01341 
01342 #ifdef DEBUG
01343     KPilotConfig::getDebugLevel(p);
01344 #endif
01345     if (!KUniqueApplication::start())
01346     {
01347         if (p->isSet("device")){
01348             // tell the running kpilotDaemon to use
01349             // this device now
01350             DCOPClient d;
01351             QString dev(p->getOption("device"));
01352             QByteArray data;
01353             QDataStream arg(data, IO_WriteOnly);
01354             arg << dev;
01355             if (d.attach()){
01356                 d.send("kpilotDaemon", "KPilotDaemonIface", "setTempDevice(QString)", data );
01357                 d.detach();
01358             }
01359         }
01360         return 0;
01361     }
01362     KUniqueApplication a(true, true);
01363 
01364     // A block just to keep variables local.
01365     //
01366     //
01367     {
01368 //      KPilotSettings::self()->config()->setReadOnly(false);
01369 
01370         if (KPilotSettings::configVersion() < KPilotConfig::ConfigurationVersion)
01371         {
01372             kdError() << k_funcinfo
01373                 << ": Is still not configured for use."
01374                 << endl;
01375             if (!p->isSet("fail-silently"))
01376             {
01377                 KPilotConfig::sorryVersionOutdated(KPilotSettings::configVersion());
01378             }
01379             return 1;
01380         }
01381 
01382 #ifdef DEBUG
01383         DEBUGKPILOT << fname
01384             << ": Configuration version "
01385             << KPilotSettings::configVersion() << endl;
01386 #endif
01387     }
01388 
01389 
01390     PilotDaemon *gPilotDaemon = new PilotDaemon();
01391 
01392     if (p->isSet("device"))
01393         gPilotDaemon->setTempDevice(p->getOption("device"));
01394 
01395     if (gPilotDaemon->status() == PilotDaemon::ERROR)
01396     {
01397         delete gPilotDaemon;
01398 
01399         gPilotDaemon = 0;
01400         kdError() << k_funcinfo
01401             << ": **\n"
01402             ": Failed to start up daemon\n"
01403             ": due to errors constructing it.\n" ": **" << endl;
01404         return 2;
01405     }
01406 
01407     gPilotDaemon->showTray();
01408 
01409     return a.exec();
01410 }
01411 
01412 
01413 
KDE Home | KDE Accessibility Home | Description of Access Keys