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