kpilot/lib

kpilotlink.cc

00001 /* KPilot
00002 **
00003 ** Copyright (C) 1998-2001 by Dan Pilone
00004 ** Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00005 ** Copyright (C) 2006 Adriaan de Groot <groot@kde.org>
00006 **
00007 */
00008 
00009 /*
00010 ** This program is free software; you can redistribute it and/or modify
00011 ** it under the terms of the GNU Lesser General Public License as published by
00012 ** the Free Software Foundation; either version 2.1 of the License, or
00013 ** (at your option) any later version.
00014 **
00015 ** This program is distributed in the hope that it will be useful,
00016 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00018 ** GNU Lesser General Public License for more details.
00019 **
00020 ** You should have received a copy of the GNU Lesser General Public License
00021 ** along with this program in a file called COPYING; if not, write to
00022 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00023 ** MA 02110-1301, USA.
00024 */
00025 
00026 /*
00027 ** Bug reports and questions can be sent to kde-pim@kde.org
00028 */
00029 
00030 #include "options.h"
00031 
00032 
00033 
00034 #include <sys/stat.h>
00035 #include <sys/types.h>
00036 #include <stdio.h>
00037 #include <unistd.h>
00038 #include <fcntl.h>
00039 #include <errno.h>
00040 
00041 #include <iostream>
00042 
00043 #include <pi-source.h>
00044 #include <pi-socket.h>
00045 #include <pi-dlp.h>
00046 #include <pi-file.h>
00047 #include <pi-buffer.h>
00048 
00049 #include <qdir.h>
00050 #include <qtimer.h>
00051 #include <qdatetime.h>
00052 #include <qsocketnotifier.h>
00053 #include <qthread.h>
00054 
00055 #include <kconfig.h>
00056 #include <kmessagebox.h>
00057 #include <kstandarddirs.h>
00058 #include <kurl.h>
00059 #include <kio/netaccess.h>
00060 
00061 #include "pilotUser.h"
00062 #include "pilotSysInfo.h"
00063 #include "pilotCard.h"
00064 #include "pilotSerialDatabase.h"
00065 #include "pilotLocalDatabase.h"
00066 
00067 #include "kpilotlink.moc"
00068 #include "kpilotdevicelink.moc"
00069 #include "kpilotlocallink.moc"
00070 
00075 class TickleThread : public QThread
00076 {
00077 public:
00078     TickleThread(KPilotLink *d, bool *done, int timeout) :
00079         QThread(),
00080         fHandle(d),
00081         fDone(done),
00082         fTimeout(timeout)
00083     { };
00084     virtual ~TickleThread();
00085 
00086     virtual void run();
00087 
00088     static const int ChecksPerSecond = 5;
00089     static const int SecondsPerTickle = 5;
00090     static const unsigned int TickleTimeoutEvent = 1066;
00091 
00092 private:
00093     KPilotLink *fHandle;
00094     bool *fDone;
00095     int fTimeout;
00096 } ;
00097 
00098 TickleThread::~TickleThread()
00099 {
00100 }
00101 
00102 void TickleThread::run()
00103 {
00104     FUNCTIONSETUP;
00105     int subseconds = ChecksPerSecond;
00106     int ticktock = SecondsPerTickle;
00107     int timeout = fTimeout;
00108     DEBUGLIBRARY << fname << ": Running for " 
00109         << timeout << " seconds." << endl;
00110     DEBUGLIBRARY << fname << ": Done @" << (void *) fDone << endl;
00111 
00112     while (!(*fDone))
00113     {
00114         QThread::msleep(1000/ChecksPerSecond);
00115         if (!(--subseconds))
00116         {
00117             if (timeout)
00118             {
00119                 if (!(--timeout))
00120                 {
00121                     QApplication::postEvent(fHandle, new QEvent(static_cast<QEvent::Type>(TickleTimeoutEvent)));
00122                     break;
00123                 }
00124             }
00125             subseconds=ChecksPerSecond;
00126             if (!(--ticktock))
00127             {
00128                 ticktock=SecondsPerTickle;
00129                 fHandle->tickle();
00130             }
00131         }
00132     }
00133 }
00134 
00135 
00136 
00137 
00138 
00139 
00140 
00141 
00142 KPilotLink::KPilotLink( QObject *parent, const char *name ) :
00143     QObject( parent, name ),
00144     fPilotPath(QString::null),
00145     fPilotUser(0L),
00146     fPilotSysInfo(0L),
00147     fTickleDone(true),
00148     fTickleThread(0L)
00149 
00150 {
00151     FUNCTIONSETUP;
00152 
00153     fPilotUser = new KPilotUser();
00154     strncpy( fPilotUser->pilotUser()->username, "Henk Westbroek",
00155         sizeof(fPilotUser->pilotUser()->username)-1);
00156     fPilotUser->setLastSuccessfulSyncDate( 1139171019 );
00157 
00158     fPilotSysInfo = new KPilotSysInfo();
00159     memset(fPilotSysInfo->sysInfo()->prodID, 0,
00160         sizeof(fPilotSysInfo->sysInfo()->prodID));
00161     strncpy(fPilotSysInfo->sysInfo()->prodID, "LocalLink",
00162         sizeof(fPilotSysInfo->sysInfo()->prodID)-1);
00163     fPilotSysInfo->sysInfo()->prodIDLength =
00164         strlen(fPilotSysInfo->sysInfo()->prodID);
00165 }
00166 
00167 KPilotLink::~KPilotLink()
00168 {
00169     FUNCTIONSETUP;
00170     KPILOT_DELETE(fPilotUser);
00171     KPILOT_DELETE(fPilotSysInfo);
00172 }
00173 
00174 /* virtual */ bool KPilotLink::event(QEvent *e)
00175 {
00176     if (e->type() == TickleThread::TickleTimeoutEvent)
00177     {
00178         stopTickle();
00179         emit timeout();
00180         return true;
00181     }
00182     else    return QObject::event(e);
00183 }
00184 
00185 /*
00186 Start a tickle thread with the indicated timeout.
00187 */
00188 void KPilotLink::startTickle(unsigned int timeout)
00189 {
00190     FUNCTIONSETUP;
00191 
00192     Q_ASSERT(fTickleDone);
00193 
00194     /*
00195     ** We've told the thread to finish up, but it hasn't
00196     ** done so yet - so wait for it to do so, should be
00197     ** only 200ms at most.
00198     */
00199     if (fTickleDone && fTickleThread)
00200     {
00201         fTickleThread->wait();
00202         KPILOT_DELETE(fTickleThread);
00203     }
00204 
00205     DEBUGLIBRARY << fname << ": Done @" << (void *) (&fTickleDone) << endl;
00206 
00207     fTickleDone = false;
00208     fTickleThread = new TickleThread(this,&fTickleDone,timeout);
00209     fTickleThread->start();
00210 }
00211 
00212 void KPilotLink::stopTickle()
00213 {
00214     FUNCTIONSETUP;
00215     fTickleDone = true;
00216     if (fTickleThread)
00217     {
00218         fTickleThread->wait();
00219         KPILOT_DELETE(fTickleThread);
00220     }
00221 }
00222 
00223 unsigned int KPilotLink::installFiles(const QStringList & l, const bool deleteFiles)
00224 {
00225     FUNCTIONSETUP;
00226 
00227     QStringList::ConstIterator i,e;
00228     unsigned int k = 0;
00229     unsigned int n = 0;
00230     unsigned int total = l.count();
00231 
00232     for (i = l.begin(), e = l.end(); i != e; ++i)
00233     {
00234         emit logProgress(QString::null,
00235             (int) ((100.0 / total) * (float) n));
00236 
00237         if (installFile(*i, deleteFiles))
00238             k++;
00239         n++;
00240     }
00241     emit logProgress(QString::null, 100);
00242 
00243     return k;
00244 }
00245 
00246 void KPilotLink::addSyncLogEntry(const QString & entry, bool log)
00247 {
00248     FUNCTIONSETUP;
00249     if (entry.isEmpty()) return;
00250 
00251     addSyncLogEntryImpl(entry);
00252     if (log)
00253     {
00254         emit logMessage(entry);
00255     }
00256 }
00257 
00258 
00259 /* virtual */ int KPilotLink::openConduit()
00260 {
00261     return 0;
00262 }
00263 
00264 /* virtual */ int KPilotLink::pilotSocket() const
00265 {
00266     return -1;
00267 }
00268 
00269 
00270 
00271 
00272 // singleton helper class
00273 class KPilotDeviceLink::KPilotDeviceLinkPrivate
00274 {
00275 public:
00276     static KPilotDeviceLinkPrivate*self()
00277     {
00278         if (!mThis) mThis = new KPilotDeviceLinkPrivate();
00279         return mThis;
00280     }
00281 
00282     bool canBind( const QString &device )
00283     {
00284         showList();
00285         return !mBoundDevices.contains( device );
00286     }
00287 
00288     void bindDevice( const QString &device )
00289     {
00290         mBoundDevices.append( device );
00291         showList();
00292     }
00293 
00294     void unbindDevice( const QString &device )
00295     {
00296         mBoundDevices.remove( device );
00297         showList();
00298     }
00299 
00300 protected:
00301     KPilotDeviceLinkPrivate() {}
00302     ~KPilotDeviceLinkPrivate() {}
00303 
00304     QStringList mBoundDevices;
00305     static KPilotDeviceLinkPrivate*mThis;
00306 
00307 private:
00308     inline void showList() const
00309     {
00310         if ( !(mBoundDevices.count() > 0) ) return;
00311         FUNCTIONSETUPL(3);
00312         DEBUGLIBRARY << fname << ": Bound devices: "
00313             << ((mBoundDevices.count() > 0) ? mBoundDevices.join(CSL1(", ")) : CSL1("<none>")) << endl;
00314     }
00315 } ;
00316 
00317 KPilotDeviceLink::KPilotDeviceLinkPrivate *KPilotDeviceLink::KPilotDeviceLinkPrivate::mThis = 0L;
00318 
00319 
00320 KPilotDeviceLink::KPilotDeviceLink(QObject * parent, const char *name, const QString &tempDevice) :
00321     KPilotLink(parent, name),
00322     fLinkStatus(Init),
00323     fWorkaroundUSB(false),
00324     fWorkaroundUSBTimer(0L),
00325     fRetries(0),
00326     fOpenTimer(0L),
00327     fSocketNotifier(0L),
00328     fSocketNotifierActive(false),
00329     fPilotMasterSocket(-1),
00330     fCurrentPilotSocket(-1),
00331     fTempDevice(tempDevice)
00332 {
00333     FUNCTIONSETUP;
00334 
00335     DEBUGLIBRARY << fname
00336         << ": Pilot-link version " << PILOT_LINK_NUMBER
00337         << endl;
00338 
00339     messagesMask=0xffffffff;
00340 
00341 }
00342 
00343 KPilotDeviceLink::~KPilotDeviceLink()
00344 {
00345     FUNCTIONSETUP;
00346     close();
00347     KPILOT_DELETE(fWorkaroundUSBTimer);
00348     KPILOT_DELETE(fPilotSysInfo);
00349     KPILOT_DELETE(fPilotUser);
00350 }
00351 
00352 /* virtual */ bool KPilotDeviceLink::isConnected() const
00353 {
00354      return fLinkStatus == AcceptedDevice;
00355 }
00356 
00357 
00358 void KPilotDeviceLink::close()
00359 {
00360     FUNCTIONSETUP;
00361 
00362     KPILOT_DELETE(fWorkaroundUSBTimer);
00363     KPILOT_DELETE(fOpenTimer);
00364     KPILOT_DELETE(fSocketNotifier);
00365     fSocketNotifierActive=false;
00366 
00367     DEBUGLIBRARY << fname
00368         << ": Closing sockets "
00369         << fCurrentPilotSocket
00370         << " and "
00371         << fPilotMasterSocket
00372         << endl;
00373 
00374     if (fCurrentPilotSocket != -1)
00375     {
00376         pi_close(fCurrentPilotSocket);
00377         // It seems that pi_close doesn't release
00378         // the file descriptor, so do that forcibly.
00379 		::close(fCurrentPilotSocket);
00380     }
00381     if (fPilotMasterSocket != -1)
00382     {
00383         pi_close(fPilotMasterSocket);
00384 		::close(fPilotMasterSocket);
00385     }
00386     KPilotDeviceLinkPrivate::self()->unbindDevice( fRealPilotPath );
00387     fPilotMasterSocket = (-1);
00388     fCurrentPilotSocket = (-1);
00389 }
00390 
00391 void KPilotDeviceLink::reset(const QString & dP)
00392 {
00393     FUNCTIONSETUP;
00394 
00395     fLinkStatus = Init;
00396     fRetries = 0;
00397 
00398     // Release all resources
00399     //
00400     close();
00401     fPilotPath = QString::null;
00402 
00403     fPilotPath = dP;
00404     if (fPilotPath.isEmpty())
00405        fPilotPath = fTempDevice;
00406     if (fPilotPath.isEmpty())
00407         return;
00408 
00409     reset();
00410 }
00411 
00412 static inline void startOpenTimer(KPilotDeviceLink *dev, QTimer *&t)
00413 {
00414     if ( !t ){
00415         t = new QTimer(dev);
00416         QObject::connect(t, SIGNAL(timeout()),
00417             dev, SLOT(openDevice()));
00418     }
00419     t->start(1000, false);
00420 }
00421 
00422 void KPilotDeviceLink::reset()
00423 {
00424     FUNCTIONSETUP;
00425 
00426     messages=0;
00427     close();
00428 
00429     checkDevice();
00430 
00431     // Timer already deleted by close() call.
00432     startOpenTimer(this,fOpenTimer);
00433 
00434     fLinkStatus = WaitingForDevice;
00435 }
00436 
00437 void KPilotDeviceLink::checkDevice()
00438 {
00439     // If the device exists yet doesn't have the right
00440     // permissions, complain and then continue anyway.
00441     //
00442     QFileInfo fi(fPilotPath);
00443     if (fi.exists())
00444     {
00445         // If it exists, it ought to be RW already.
00446         //
00447         if (!(fi.isReadable() && fi.isWritable()))
00448         {
00449             emit logError(i18n("Pilot device %1 is not read-write.")
00450                 .arg(fPilotPath));
00451         }
00452     }
00453     else
00454     {
00455         // It doesn't exist, mention this in the log
00456         // (relevant as long as we use only one device type)
00457         //
00458         emit logError(i18n("Pilot device %1 does not exist. "
00459             "Probably it is a USB device and will appear during a HotSync.")
00460                 .arg(fPilotPath));
00461         messages |= (OpenMessage | OpenFailMessage);
00462     }
00463 }
00464 
00465 void KPilotDeviceLink::setTempDevice( const QString &d )
00466 {
00467     fTempDevice = d;
00468     KPilotDeviceLinkPrivate::self()->bindDevice( fTempDevice );
00469 }
00470 
00471 void KPilotDeviceLink::openDevice()
00472 {
00473     FUNCTIONSETUPL(2);
00474 
00475     // This transition (from Waiting to Found) can only be
00476     // taken once.
00477     //
00478     if (fLinkStatus == WaitingForDevice)
00479     {
00480         fLinkStatus = FoundDevice;
00481     }
00482 
00483     shouldPrint(OpenMessage,i18n("Trying to open device %1...")
00484         .arg(fPilotPath));
00485 
00486     if (open())
00487     {
00488         emit logMessage(i18n("Device link ready."));
00489     }
00490     else if (open(fTempDevice))
00491     {
00492         emit logMessage(i18n("Device link ready."));
00493     }
00494     else
00495     {
00496         shouldPrint(OpenFailMessage,i18n("Could not open device: %1 "
00497                 "(will retry)").
00498                 arg(fPilotPath));
00499 
00500         if (fLinkStatus != PilotLinkError)
00501         {
00502             startOpenTimer(this,fOpenTimer);
00503         }
00504     }
00505 }
00506 
00507 bool KPilotDeviceLink::open(const QString &device)
00508 {
00509     FUNCTIONSETUPL(2);
00510 
00511     int ret;
00512     int e = 0;
00513     QString msg;
00514 
00515     if (fCurrentPilotSocket != -1)
00516     {
00517         // See note in KPilotDeviceLink::close()
00518         pi_close(fCurrentPilotSocket);
00519 		::close(fCurrentPilotSocket);
00520     }
00521     fCurrentPilotSocket = (-1);
00522 
00523     if (device.isEmpty() && pilotPath().isEmpty())
00524     {
00525         kdWarning() << k_funcinfo
00526             << ": No point in trying empty device."
00527             << endl;
00528 
00529         msg = i18n("The Pilot device is not configured yet.");
00530         e = 0;
00531         goto errInit;
00532     }
00533     fRealPilotPath = KStandardDirs::realFilePath( device.isEmpty() ? fPilotPath : device );
00534 
00535     if ( !KPilotDeviceLinkPrivate::self()->canBind( fRealPilotPath ) ) {
00536         msg = i18n("Already listening on that device");
00537         e=0;
00538         kdWarning() << k_funcinfo << ": Pilot Path "
00539             << fRealPilotPath << " already connected." << endl;
00540         goto errInit;
00541     }
00542 
00543 
00544     if (fPilotMasterSocket == -1)
00545     {
00546         DEBUGLIBRARY << fname << ": Typing to open "
00547             << fRealPilotPath << endl;
00548 
00549         fPilotMasterSocket = pi_socket(PI_AF_PILOT,
00550             PI_SOCK_STREAM, PI_PF_DLP);
00551 
00552         if (fPilotMasterSocket < 0)
00553         {
00554             e = errno;
00555             msg = i18n("Cannot create socket for communicating "
00556                 "with the Pilot");
00557             goto errInit;
00558         }
00559 
00560         DEBUGLIBRARY << fname
00561             << ": Got master " << fPilotMasterSocket << endl;
00562 
00563         fLinkStatus = CreatedSocket;
00564     }
00565 
00566     Q_ASSERT(fLinkStatus == CreatedSocket);
00567 
00568     DEBUGLIBRARY << fname << ": Binding to path "
00569         << fRealPilotPath << endl;
00570 
00571     ret = pi_bind(fPilotMasterSocket, QFile::encodeName(fRealPilotPath));
00572 
00573     if (ret >= 0)
00574     {
00575         fLinkStatus = DeviceOpen;
00576         if( fOpenTimer)
00577         fOpenTimer->stop();
00578 
00579         KPilotDeviceLinkPrivate::self()->bindDevice( fRealPilotPath );
00580         fSocketNotifier = new QSocketNotifier(fPilotMasterSocket,
00581             QSocketNotifier::Read, this);
00582         QObject::connect(fSocketNotifier, SIGNAL(activated(int)),
00583             this, SLOT(acceptDevice()));
00584         fSocketNotifierActive=true;
00585 
00586         if (fWorkaroundUSB)
00587         {
00588             DEBUGLIBRARY << fname << ": Adding Z31 workaround." << endl;
00589             // Special case for Zire 31, 72, Tungsten T5,
00590             // all of which may make a non-HotSync connection
00591             // to the PC. Must detect this and bail quickly.
00592             //
00593             fWorkaroundUSBTimer = new QTimer(this);
00594             connect(fWorkaroundUSBTimer,SIGNAL(timeout()),
00595                 this,SLOT(workaroundUSB()));
00596             fWorkaroundUSBTimer->start(5000,true);
00597         }
00598 
00599         return true;
00600     }
00601     else
00602     {
00603         DEBUGLIBRARY << fname
00604             << ": Tried " << fRealPilotPath << " and got "
00605             << strerror(errno) << endl;
00606 
00607         if (fRetries < 5)
00608         {
00609             return false;
00610         }
00611         e = errno;
00612         msg = i18n("Cannot open Pilot port \"%1\". ");
00613         if (fOpenTimer )
00614             fOpenTimer->stop();
00615 
00616         // goto errInit;
00617     }
00618 
00619 
00620 // We arrive here when some action for initializing the sockets
00621 // has gone wrong, and we need to log that and alert the user
00622 // that it has gone wrong.
00623 //
00624 //
00625 errInit:
00626     close();
00627 
00628     if (msg.find('%'))
00629     {
00630         if (fRealPilotPath.isEmpty())
00631         {
00632             if (fPilotPath.isEmpty())
00633             {
00634                 msg = msg.arg(i18n("(empty)"));
00635             }
00636             else
00637             {
00638                 msg = msg.arg(fPilotPath);
00639             }
00640         }
00641         else
00642         {
00643             msg = msg.arg(fRealPilotPath);
00644         }
00645     }
00646     switch (e)
00647     {
00648     case ENOENT:
00649         msg += i18n(" The port does not exist.");
00650         break;
00651     case ENODEV:
00652         msg += i18n(" These is no such device.");
00653         break;
00654     case EPERM:
00655         msg += i18n(" You do not have permission to open the "
00656             "Pilot device.");
00657         break;
00658     default:
00659         msg += i18n(" Check Pilot path and permissions.");
00660     }
00661 
00662     // OK, so we may have to deal with a translated
00663     // error message here. Big deal -- we have the line
00664     // number as well, right?
00665     //
00666     //
00667     kdError() << k_funcinfo << ": " << msg << endl;
00668     if (e)
00669     {
00670         kdError() << k_funcinfo
00671             << ": (" << strerror(e) << ")" << endl;
00672     }
00673 
00674     fLinkStatus = PilotLinkError;
00675     emit logError(msg);
00676     return false;
00677 }
00678 
00679 void KPilotDeviceLink::acceptDevice()
00680 {
00681     FUNCTIONSETUP;
00682 
00683     int ret;
00684 
00685     if (!fSocketNotifierActive)
00686     {
00687         if (!fAcceptedCount)
00688         {
00689         kdWarning() << k_funcinfo << ": Accidentally in acceptDevice()"
00690             << endl;
00691         }
00692         fAcceptedCount++;
00693         if (fAcceptedCount>10)
00694         {
00695             // Damn the torpedoes
00696             KPILOT_DELETE(fSocketNotifier);
00697         }
00698         return;
00699     }
00700 
00701     if (fSocketNotifier)
00702     {
00703         // fSocketNotifier->setEnabled(false);
00704         fSocketNotifierActive=false;
00705     }
00706 
00707     DEBUGLIBRARY << fname
00708         << ": Found connection on device "<<pilotPath().latin1()<<endl;
00709     DEBUGLIBRARY << fname
00710         << ": Current status "
00711         << statusString()
00712         << " and master " << fPilotMasterSocket << endl;
00713 
00714     ret = pi_listen(fPilotMasterSocket, 1);
00715     if (ret < 0)
00716     {
00717         char *s = strerror(errno);
00718 
00719         kdWarning() << "pi_listen: " << s << endl;
00720 
00721         // Presumably, strerror() returns things in
00722         // local8Bit and not latin1.
00723         emit logError(i18n("Cannot listen on Pilot socket (%1)").
00724             arg(QString::fromLocal8Bit(s)));
00725 
00726         close();
00727         return;
00728     }
00729 
00730     KPILOT_DELETE(fWorkaroundUSBTimer);
00731 
00732     emit logProgress(QString::null,10);
00733 
00734     fCurrentPilotSocket = pi_accept(fPilotMasterSocket, 0, 0);
00735     if (fCurrentPilotSocket < 0)
00736     {
00737         char *s = strerror(errno);
00738 
00739         kdWarning() << "pi_accept: " << s << endl;
00740 
00741         emit logError(i18n("Cannot accept Pilot (%1)")
00742             .arg(QString::fromLocal8Bit(s)));
00743 
00744         fLinkStatus = PilotLinkError;
00745         close();
00746         return;
00747     }
00748 
00749     if ((fLinkStatus != DeviceOpen) || (fPilotMasterSocket == -1))
00750     {
00751         fLinkStatus = PilotLinkError;
00752         kdError() << k_funcinfo
00753             << ": Already connected or unable to connect!"
00754             << endl;
00755         emit logError(i18n("Cannot accept Pilot (%1)")
00756             .arg(i18n("already connected")));
00757         close();
00758         return;
00759     }
00760 
00761     emit logProgress(QString::null, 30);
00762 
00763         KPILOT_DELETE(fPilotSysInfo);
00764     fPilotSysInfo = new KPilotSysInfo();
00765     if (dlp_ReadSysInfo(fCurrentPilotSocket, fPilotSysInfo->sysInfo()) < 0)
00766     {
00767         emit logError(i18n("Unable to read system information from Pilot"));
00768         fLinkStatus=PilotLinkError;
00769         return;
00770     }
00771     else
00772     {
00773         DEBUGLIBRARY << fname
00774             << ": RomVersion=" << fPilotSysInfo->getRomVersion()
00775             << " Locale=" << fPilotSysInfo->getLocale()
00776             << " Product=" << fPilotSysInfo->getProductID()
00777             << endl;
00778     }
00779 
00780     emit logProgress(QString::null, 60);
00781         KPILOT_DELETE(fPilotUser);
00782     fPilotUser = new KPilotUser;
00783 
00784     /* Ask the pilot who it is.  And see if it's who we think it is. */
00785     DEBUGLIBRARY << fname << ": Reading user info @"
00786         << (void *) fPilotUser << endl;
00787     DEBUGLIBRARY << fname << ": Buffer @"
00788         << (void *) fPilotUser->pilotUser() << endl;
00789 
00790     dlp_ReadUserInfo(fCurrentPilotSocket, fPilotUser->pilotUser());
00791 
00792     const char *n = fPilotUser->getUserName();
00793     DEBUGLIBRARY << fname
00794         << ": Read user name "
00795         << ( (!n || !*n) ?
00796             "<empty>" :
00797             fPilotUser->getUserName() )
00798         << endl;
00799 
00800     emit logProgress(i18n("Checking last PC..."), 90);
00801 
00802     /* Tell user (via Pilot) that we are starting things up */
00803     if ((ret=dlp_OpenConduit(fCurrentPilotSocket)) < 0)
00804     {
00805         DEBUGLIBRARY << fname
00806             << ": dlp_OpenConduit returned " << ret << endl;
00807 
00808         emit logError(i18n("Could not read user information from the Pilot. "
00809             "Perhaps you have a password set on the device?"));
00810     }
00811     fLinkStatus = AcceptedDevice;
00812 
00813 
00814     emit logProgress(QString::null, 100);
00815     emit deviceReady( this );
00816 }
00817 
00818 void KPilotDeviceLink::workaroundUSB()
00819 {
00820     FUNCTIONSETUP;
00821 
00822     Q_ASSERT((fLinkStatus == DeviceOpen) || (fLinkStatus == WorkaroundUSB));
00823     if (fLinkStatus == DeviceOpen)
00824     {
00825         reset();
00826     }
00827     fLinkStatus = WorkaroundUSB;
00828 
00829     if (!QFile::exists(fRealPilotPath))
00830     {
00831         // Fake connection has vanished again.
00832         // Resume polling for regular connection.
00833         startOpenTimer(this,fOpenTimer);
00834         return;
00835     }
00836     if (fOpenTimer)
00837     {
00838         fOpenTimer->stop();
00839     }
00840     KPILOT_DELETE(fWorkaroundUSBTimer);
00841     QTimer::singleShot(1000,this,SLOT(workaroundUSB()));
00842 }
00843 
00844 /* virtual */ bool KPilotDeviceLink::tickle()
00845 {
00846     // No FUNCTIONSETUP here because it may be called from
00847     // a separate thread.
00848     return pi_tickle(pilotSocket()) >= 0;
00849 }
00850 
00851 /* virtual */ void KPilotDeviceLink::addSyncLogEntryImpl( const QString &entry )
00852 {
00853     dlp_AddSyncLogEntry(fCurrentPilotSocket,
00854         const_cast<char *>((const char *)Pilot::toPilot(entry)));
00855 }
00856 
00857 bool KPilotDeviceLink::installFile(const QString & f, const bool deleteFile)
00858 {
00859     FUNCTIONSETUP;
00860 
00861     DEBUGLIBRARY << fname << ": Installing file " << f << endl;
00862 
00863     if (!QFile::exists(f))
00864         return false;
00865 
00866     char buffer[PATH_MAX];
00867     memset(buffer,0,PATH_MAX);
00868     strlcpy(buffer,QFile::encodeName(f),PATH_MAX);
00869     struct pi_file *pf =
00870         pi_file_open(buffer);
00871 
00872     if (!f)
00873     {
00874         kdWarning() << k_funcinfo
00875             << ": Cannot open file " << f << endl;
00876         emit logError(i18n
00877             ("<qt>Cannot install the file &quot;%1&quot;.</qt>").
00878             arg(f));
00879         return false;
00880     }
00881 
00882     if (pi_file_install(pf, fCurrentPilotSocket, 0, 0L) < 0)
00883     {
00884         kdWarning() << k_funcinfo
00885             << ": Cannot pi_file_install " << f << endl;
00886         emit logError(i18n
00887             ("<qt>Cannot install the file &quot;%1&quot;.</qt>").
00888             arg(f));
00889         return false;
00890     }
00891 
00892     pi_file_close(pf);
00893     if (deleteFile) QFile::remove(f);
00894 
00895     return true;
00896 }
00897 
00898 
00899 int KPilotDeviceLink::openConduit()
00900 {
00901     return dlp_OpenConduit(fCurrentPilotSocket);
00902 }
00903 
00904 QString KPilotDeviceLink::statusString(LinkStatus l)
00905 {
00906     FUNCTIONSETUP;
00907     QString s = CSL1("KPilotDeviceLink=");
00908 
00909     switch (l)
00910     {
00911     case Init:
00912         s.append(CSL1("Init"));
00913         break;
00914     case WaitingForDevice:
00915         s.append(CSL1("WaitingForDevice"));
00916         break;
00917     case FoundDevice:
00918         s.append(CSL1("FoundDevice"));
00919         break;
00920     case CreatedSocket:
00921         s.append(CSL1("CreatedSocket"));
00922         break;
00923     case DeviceOpen:
00924         s.append(CSL1("DeviceOpen"));
00925         break;
00926     case AcceptedDevice:
00927         s.append(CSL1("AcceptedDevice"));
00928         break;
00929     case SyncDone:
00930         s.append(CSL1("SyncDone"));
00931         break;
00932     case PilotLinkError:
00933         s.append(CSL1("PilotLinkError"));
00934         break;
00935     case WorkaroundUSB:
00936         s.append(CSL1("WorkaroundUSB"));
00937         break;
00938     }
00939 
00940     return s;
00941 }
00942 
00943 QString KPilotDeviceLink::statusString() const
00944 {
00945     return statusString( status() );
00946 }
00947 
00948 void KPilotDeviceLink::endOfSync()
00949 {
00950     dlp_EndOfSync(pilotSocket(), 0);
00951     KPILOT_DELETE(fPilotSysInfo);
00952     KPILOT_DELETE(fPilotUser);
00953 }
00954 
00955 void KPilotDeviceLink::finishSync()
00956 {
00957     FUNCTIONSETUP ;
00958 
00959     getPilotUser().setLastSyncPC((unsigned long) gethostid());
00960     getPilotUser().setLastSyncDate(time(0));
00961 
00962 
00963     DEBUGLIBRARY << fname << ": Writing username " << getPilotUser().getUserName() << endl;
00964 
00965     dlp_WriteUserInfo(pilotSocket(),getPilotUser().pilotUser());
00966     addSyncLogEntry(i18n("End of HotSync\n"));
00967     endOfSync();
00968 }
00969 
00970 int KPilotDeviceLink::getNextDatabase(int index,struct DBInfo *dbinfo)
00971 {
00972     FUNCTIONSETUP;
00973 
00974     pi_buffer_t buf = { 0,0,0 };
00975     int r = dlp_ReadDBList(pilotSocket(),0,dlpDBListRAM,index,&buf);
00976     if (r >= 0)
00977     {
00978         memcpy(dbinfo,buf.data,sizeof(struct DBInfo));
00979     }
00980     return r;
00981 }
00982 
00983 // Find a database with the given name. Info about the DB is stored into dbinfo (e.g. to be used later on with retrieveDatabase).
00984 int KPilotDeviceLink::findDatabase(const char *name, struct DBInfo *dbinfo,
00985     int index, unsigned long type, unsigned long creator)
00986 {
00987     FUNCTIONSETUP;
00988     return dlp_FindDBInfo(pilotSocket(), 0, index,
00989         const_cast<char *>(name), type, creator, dbinfo);
00990 }
00991 
00992 bool KPilotDeviceLink::retrieveDatabase(const QString &fullBackupName,
00993     DBInfo *info)
00994 {
00995     FUNCTIONSETUP;
00996 
00997     DEBUGLIBRARY << fname << ": Writing DB <" << info->name << "> "
00998         << " to " << fullBackupName << endl;
00999 
01000     struct pi_file *f;
01001     if (fullBackupName.isEmpty())
01002     {
01003         // Don't even bother trying to convert or retrieve.
01004         return false;
01005     }
01006     QCString encodedName = QFile::encodeName(fullBackupName);
01007     char filenameBuf[PATH_MAX];
01008     memset(filenameBuf,0,PATH_MAX);
01009     strlcpy(filenameBuf,(const char *)encodedName,PATH_MAX);
01010     f = pi_file_create(filenameBuf,info);
01011 
01012     if (f == 0)
01013     {
01014         kdWarning() << k_funcinfo
01015             << ": Failed, unable to create file" << endl;
01016         return false;
01017     }
01018 
01019     if (pi_file_retrieve(f, pilotSocket(), 0, 0L) < 0)
01020     {
01021         kdWarning() << k_funcinfo
01022             << ": Failed, unable to back up database" << endl;
01023 
01024         pi_file_close(f);
01025         return false;
01026     }
01027 
01028     pi_file_close(f);
01029     return true;
01030 }
01031 
01032 
01033 DBInfoList KPilotDeviceLink::getDBList(int cardno, int flags)
01034 {
01035     bool cont=true;
01036     DBInfoList dbs;
01037     int index=0;
01038     while (cont)
01039     {
01040         pi_buffer_t buf = { 0,0,0 };
01041         pi_buffer_clear(&buf);
01042         // DBInfo*dbi=new DBInfo();
01043         if (dlp_ReadDBList(pilotSocket(), cardno, flags | dlpDBListMultiple, index, &buf)<0)
01044         {
01045             cont=false;
01046         }
01047         else
01048         {
01049             DBInfo db_n;
01050             DBInfo *db_it = (DBInfo *)buf.data;
01051             int info_count = buf.used / sizeof(struct DBInfo);
01052 
01053             while(info_count>0)
01054             {
01055                 memcpy(&db_n,db_it,sizeof(struct DBInfo));
01056                 ++db_it;
01057                 info_count--;
01058                 dbs.append(db_n);
01059             }
01060             index=db_n.index+1;
01061         }
01062     }
01063     return dbs;
01064 }
01065 
01066 const KPilotCard *KPilotDeviceLink::getCardInfo(int card)
01067 {
01068     KPilotCard *cardinfo=new KPilotCard();
01069     if (dlp_ReadStorageInfo(pilotSocket(), card, cardinfo->cardInfo())<0)
01070     {
01071         kdWarning() << k_funcinfo << ": Could not get info for card "
01072             << card << endl;
01073 
01074         KPILOT_DELETE(cardinfo);
01075         return 0L;
01076     };
01077     return cardinfo;
01078 }
01079 
01080 /* static */ const int KPilotDeviceLink::messagesType=
01081     (int)OpenFailMessage ;
01082 
01083 void KPilotDeviceLink::shouldPrint(int m,const QString &s)
01084 {
01085     if (!(messages & m))
01086     {
01087         if (messagesType & m) { emit logError(s); }
01088         else { emit logMessage(s); }
01089         messages |= (m & messagesMask);
01090     }
01091 }
01092 
01093 PilotDatabase *KPilotDeviceLink::database( const QString &name )
01094 {
01095     return new PilotSerialDatabase( this, name );
01096 }
01097 
01098 
01099 typedef QPair<QString, struct DBInfo> DatabaseDescriptor;
01100 typedef QValueList<DatabaseDescriptor> DatabaseDescriptorList;
01101 
01102 class KPilotLocalLink::Private
01103 {
01104 public:
01105     DatabaseDescriptorList fDBs;
01106 } ;
01107 
01108 unsigned int KPilotLocalLink::findAvailableDatabases( KPilotLocalLink::Private &info, const QString &path )
01109 {
01110     FUNCTIONSETUP;
01111 
01112     info.fDBs.clear();
01113 
01114     QDir d(path);
01115     if (!d.exists())
01116     {
01117         // Perhaps return an error?
01118         return 0;
01119     }
01120 
01121     // Use this to fake indexes in the list of DBInfo structs
01122     unsigned int counter = 0;
01123 
01124     QStringList dbs = d.entryList( CSL1("*.pdb"), QDir::Files | QDir::NoSymLinks | QDir::Readable );
01125     for ( QStringList::ConstIterator i = dbs.begin(); i != dbs.end() ; ++i)
01126     {
01127         struct DBInfo dbi;
01128 
01129         // Remove the trailing 4 characters
01130         QString dbname = (*i);
01131         dbname.remove(dbname.length()-4,4);
01132 
01133         QString dbnamecheck = (*i).left((*i).findRev(CSL1(".pdb")));
01134         Q_ASSERT(dbname == dbnamecheck);
01135 
01136         if (PilotLocalDatabase::infoFromFile( path + CSL1("/") + (*i), &dbi))
01137         {
01138             DEBUGLIBRARY << fname << ": Loaded "
01139                 << dbname << endl;
01140             dbi.index = counter;
01141             info.fDBs.append( DatabaseDescriptor(dbname,dbi) );
01142             ++counter;
01143         }
01144     }
01145 
01146     DEBUGLIBRARY << fname << ": Total " << info.fDBs.count()
01147         << " databases." << endl;
01148     return info.fDBs.count();
01149 }
01150 
01151 
01152 KPilotLocalLink::KPilotLocalLink( QObject *parent, const char *name ) :
01153     KPilotLink(parent,name),
01154     fReady(false),
01155     d( new Private )
01156 {
01157     FUNCTIONSETUP;
01158 }
01159 
01160 KPilotLocalLink::~KPilotLocalLink()
01161 {
01162     FUNCTIONSETUP;
01163     KPILOT_DELETE(d);
01164 }
01165 
01166 /* virtual */ QString KPilotLocalLink::statusString() const
01167 {
01168     return fReady ? CSL1("Ready") : CSL1("Waiting") ;
01169 }
01170 
01171 /* virtual */ bool KPilotLocalLink::isConnected() const
01172 {
01173     return fReady;
01174 }
01175 
01176 /* virtual */ void KPilotLocalLink::reset( const QString &p )
01177 {
01178     FUNCTIONSETUP;
01179     fPath = p;
01180     reset();
01181 }
01182 
01183 /* virtual */ void KPilotLocalLink::reset()
01184 {
01185     FUNCTIONSETUP;
01186     QFileInfo info( fPath );
01187     fReady = !fPath.isEmpty() && info.exists() && info.isDir() ;
01188     if (fReady)
01189     {
01190         findAvailableDatabases(*d, fPath);
01191         QTimer::singleShot(500,this,SLOT(ready()));
01192     }
01193     else
01194     {
01195         kdWarning() << k_funcinfo << ": The local link path "
01196             << fPath
01197             << " does not exist or is not a direcotory. No sync will be done."
01198             << endl;
01199     }
01200 }
01201 
01202 /* virtual */ void KPilotLocalLink::close()
01203 {
01204     fReady = false;
01205 }
01206 
01207 /* virtual */ bool KPilotLocalLink::tickle()
01208 {
01209     return true;
01210 }
01211 
01212 /* virtual */ const KPilotCard *KPilotLocalLink::getCardInfo(int)
01213 {
01214     return 0;
01215 }
01216 
01217 /* virtual */ void KPilotLocalLink::endOfSync()
01218 {
01219 }
01220 
01221 /* virtual */ void KPilotLocalLink::finishSync()
01222 {
01223 }
01224 
01225 /* virtual */ int KPilotLocalLink::openConduit()
01226 {
01227     FUNCTIONSETUP;
01228     return 0;
01229 }
01230 
01231 
01232 /* virtual */ int KPilotLocalLink::getNextDatabase( int index, struct DBInfo *info )
01233 {
01234     FUNCTIONSETUP;
01235 
01236     if ( (index<0) || (index>=(int)d->fDBs.count()) )
01237     {
01238         kdWarning() << k_funcinfo << ": Index out of range." << endl;
01239         return -1;
01240     }
01241 
01242     DatabaseDescriptor dd = d->fDBs[index];
01243 
01244     DEBUGLIBRARY << fname << ": Getting database " << dd.first << endl;
01245 
01246     if (info)
01247     {
01248         *info = dd.second;
01249     }
01250 
01251     return index+1;
01252 }
01253 
01254 /* virtual */ int KPilotLocalLink::findDatabase(const char *name, struct DBInfo*info,
01255         int index, unsigned long type, unsigned long creator)
01256 {
01257     FUNCTIONSETUP;
01258 
01259     if ( (index<0) || (index>=(int)d->fDBs.count()) )
01260     {
01261         kdWarning() << k_funcinfo << ": Index out of range." << endl;
01262         return -1;
01263     }
01264 
01265     if (!name)
01266     {
01267         kdWarning() << k_funcinfo << ": NULL name." << endl;
01268         return -1;
01269     }
01270 
01271     QString desiredName = Pilot::fromPilot(name);
01272     DEBUGLIBRARY << fname << ": Looking for DB " << desiredName << endl;
01273     for ( DatabaseDescriptorList::ConstIterator i = d->fDBs.at(index);
01274         i != d->fDBs.end(); ++i)
01275     {
01276         const DatabaseDescriptor &dd = *i;
01277         if (dd.first == desiredName)
01278         {
01279             if ( (!type || (type == dd.second.type)) &&
01280                 (!creator || (creator == dd.second.creator)) )
01281             {
01282                 if (info)
01283                 {
01284                     *info = dd.second;
01285                 }
01286                 return index;
01287             }
01288         }
01289 
01290         ++index;
01291     }
01292 
01293     return -1;
01294 }
01295 
01296 /* virtual */ void KPilotLocalLink::addSyncLogEntryImpl(QString const &s)
01297 {
01298     FUNCTIONSETUP;
01299     DEBUGLIBRARY << fname << ": " << s << endl ;
01300 }
01301 
01302 /* virtual */ bool KPilotLocalLink::installFile(QString const &path, bool deletefile)
01303 {
01304     FUNCTIONSETUP;
01305 
01306     QFileInfo srcInfo(path);
01307     QString canonicalSrcPath = srcInfo.dir().canonicalPath() + CSL1("/") + srcInfo.fileName() ;
01308     QString canonicalDstPath = fPath + CSL1("/") + srcInfo.fileName();
01309 
01310     if (canonicalSrcPath == canonicalDstPath)
01311     {
01312         // That's a cheap copy operation
01313         return true;
01314     }
01315 
01316     KURL src = KURL::fromPathOrURL( canonicalSrcPath );
01317     KURL dst = KURL::fromPathOrURL( canonicalDstPath );
01318 
01319     KIO::NetAccess::file_copy(src,dst,-1,true);
01320 
01321     if (deletefile)
01322     {
01323         KIO::NetAccess::del(src, 0L);
01324     }
01325 
01326     return true;
01327 }
01328 
01329 /* virtual */ bool KPilotLocalLink::retrieveDatabase( const QString &path, struct DBInfo *db )
01330 {
01331     FUNCTIONSETUP;
01332 
01333     QString dbname = Pilot::fromPilot(db->name) + CSL1(".pdb") ;
01334     QString sourcefile = fPath + CSL1("/") + dbname ;
01335     QString destfile = path ;
01336 
01337     DEBUGLIBRARY << fname << ": src=" << sourcefile << endl;
01338     DEBUGLIBRARY << fname << ": dst=" << destfile << endl;
01339 
01340     QFile in( sourcefile );
01341     if ( !in.exists() )
01342     {
01343         kdWarning() << k_funcinfo<< ": Source file " << sourcefile << " doesn't exist." << endl;
01344         return false;
01345     }
01346     if ( !in.open( IO_ReadOnly | IO_Raw ) )
01347     {
01348         kdWarning() << k_funcinfo << ": Can't read source file " << sourcefile << endl;
01349         return false;
01350     }
01351 
01352     QFile out( destfile );
01353     if ( !out.open( IO_WriteOnly | IO_Truncate | IO_Raw ) )
01354     {
01355         kdWarning() << k_funcinfo << ": Can't write destination file " << destfile << endl;
01356         return false;
01357     }
01358 
01359     const Q_ULONG BUF_SIZ = 8192 ;
01360     char buf[BUF_SIZ];
01361     Q_LONG r;
01362 
01363     while ( (r=in.readBlock(buf,BUF_SIZ))>0 )
01364     {
01365         out.writeBlock(buf,r);
01366     }
01367     out.flush();
01368     in.close();
01369 
01370     return out.exists();
01371 }
01372 
01373 /* virtual */ DBInfoList KPilotLocalLink::getDBList( int, int )
01374 {
01375     FUNCTIONSETUP;
01376     DBInfoList l;
01377     for ( DatabaseDescriptorList::ConstIterator i=d->fDBs.begin();
01378         i != d->fDBs.end(); ++i)
01379     {
01380         l.append( (*i).second );
01381     }
01382     return l;
01383 }
01384 
01385 
01386 /* virtual */ PilotDatabase *KPilotLocalLink::database( const QString &name )
01387 {
01388     FUNCTIONSETUP;
01389     return new PilotLocalDatabase( fPath, name );
01390 }
01391 
01392 
01393 
01394 /* slot */ void KPilotLocalLink::ready()
01395 {
01396     if (fReady)
01397     {
01398         emit deviceReady(this);
01399     }
01400 }
01401 
KDE Home | KDE Accessibility Home | Description of Access Keys