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 **
00006 */
00007 
00008 /*
00009 ** This program is free software; you can redistribute it and/or modify
00010 ** it under the terms of the GNU Lesser General Public License as published by
00011 ** the Free Software Foundation; either version 2.1 of the License, or
00012 ** (at your option) any later version.
00013 **
00014 ** This program is distributed in the hope that it will be useful,
00015 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017 ** GNU Lesser General Public License for more details.
00018 **
00019 ** You should have received a copy of the GNU Lesser General Public License
00020 ** along with this program in a file called COPYING; if not, write to
00021 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00022 ** MA 02110-1301, USA.
00023 */
00024 
00025 /*
00026 ** Bug reports and questions can be sent to kde-pim@kde.org
00027 */
00028 static const char *kpilotlink_id = "$Id: kpilotlink.cc 444649 2005-08-10 13:21:07Z mlaurent $";
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 #if !(PILOT_LINK_NUMBER < PILOT_LINK_0_12_0)
00048 #include <pi-buffer.h>
00049 #endif
00050 
00051 #include <qdir.h>
00052 #include <qtimer.h>
00053 #include <qdatetime.h>
00054 #include <qsocketnotifier.h>
00055 #include <qthread.h>
00056 #include <qtextcodec.h>
00057 
00058 #include <kconfig.h>
00059 #include <kmessagebox.h>
00060 #include <kstandarddirs.h>
00061 
00062 #include "pilotUser.h"
00063 #include "pilotSysInfo.h"
00064 #include "pilotCard.h"
00065 #include "pilotAppCategory.h"
00066 
00067 #include "kpilotlink.moc"
00068 
00069 
00070 // singleton helper class
00071 class KPilotDeviceLink::KPilotDeviceLinkPrivate
00072 {
00073 public:
00074     static KPilotDeviceLinkPrivate*self()
00075     {
00076         if (!mThis) mThis = new KPilotDeviceLinkPrivate();
00077         return mThis;
00078     }
00079 
00080     bool canBind( QString device )
00081     {
00082         showList();
00083         return !mBoundDevices.contains( device );
00084     }
00085 
00086     void bindDevice( QString device )
00087     {
00088         mBoundDevices.append( device );
00089         showList();
00090     }
00091 
00092     void unbindDevice( QString device )
00093     {
00094         mBoundDevices.remove( device );
00095         showList();
00096     }
00097 
00098 protected:
00099     KPilotDeviceLinkPrivate() {}
00100     ~KPilotDeviceLinkPrivate() {}
00101 
00102     QStringList mBoundDevices;
00103     static KPilotDeviceLinkPrivate*mThis;
00104 
00105 private:
00106     inline void showList() const
00107     {
00108 #ifdef DEBUG
00109         FUNCTIONSETUPL(3);
00110         DEBUGDAEMON << fname << "Bound devices: "
00111             << ((mBoundDevices.count() > 0) ? mBoundDevices.join(CSL1(", ")) : CSL1("<none>")) << endl;
00112 #endif
00113     }
00114 } ;
00115 
00116 KPilotDeviceLink::KPilotDeviceLinkPrivate *KPilotDeviceLink::KPilotDeviceLinkPrivate::mThis = 0L;
00117 
00118 
00119 KPilotDeviceLink::KPilotDeviceLink(QObject * parent, const char *name, const QString &tempDevice) :
00120     QObject(parent, name),
00121     fLinkStatus(Init),
00122     fTickleDone(true),
00123     fTickleThread(0L),
00124     fWorkaroundUSB(false),
00125     fWorkaroundUSBTimer(0L),
00126     fPilotPath(QString::null),
00127     fRetries(0),
00128     fOpenTimer(0L),
00129     fSocketNotifier(0L),
00130     fSocketNotifierActive(false),
00131     fPilotMasterSocket(-1),
00132     fCurrentPilotSocket(-1),
00133     fTempDevice(tempDevice),
00134     fPilotUser(0L),
00135     fPilotSysInfo(0L)
00136 {
00137     FUNCTIONSETUP;
00138 
00139 #ifdef DEBUG
00140     DEBUGDAEMON << fname
00141         << ": Pilot-link version " << PILOT_LINK_NUMBER
00142         << endl;
00143 #endif
00144 
00145     messagesMask=0xffffffff;
00146 
00147     (void) kpilotlink_id;
00148 }
00149 
00150 KPilotDeviceLink::~KPilotDeviceLink()
00151 {
00152     FUNCTIONSETUP;
00153     close();
00154     KPILOT_DELETE(fWorkaroundUSBTimer);
00155     KPILOT_DELETE(fPilotSysInfo);
00156     KPILOT_DELETE(fPilotUser);
00157 }
00158 
00159 void KPilotDeviceLink::close()
00160 {
00161     FUNCTIONSETUP;
00162 
00163     KPILOT_DELETE(fWorkaroundUSBTimer);
00164     KPILOT_DELETE(fOpenTimer);
00165     KPILOT_DELETE(fSocketNotifier);
00166     fSocketNotifierActive=false;
00167 #ifdef DEBUG
00168     DEBUGDAEMON << fname
00169         << ": Closing sockets "
00170         << fCurrentPilotSocket
00171         << " and "
00172         << fPilotMasterSocket
00173         << endl;
00174 #endif
00175     if (fCurrentPilotSocket != -1)
00176     {
00177         pi_close(fCurrentPilotSocket);
00178         // It seems that pi_close doesn't release
00179         // the file descriptor, so do that forcibly.
00180 		::close(fCurrentPilotSocket);
00181     }
00182     if (fPilotMasterSocket != -1)
00183     {
00184         pi_close(fPilotMasterSocket);
00185 		::close(fPilotMasterSocket);
00186     }
00187     KPilotDeviceLinkPrivate::self()->unbindDevice( fRealPilotPath );
00188     fPilotMasterSocket = (-1);
00189     fCurrentPilotSocket = (-1);
00190 }
00191 
00192 void KPilotDeviceLink::reset(const QString & dP)
00193 {
00194     FUNCTIONSETUP;
00195 
00196     fLinkStatus = Init;
00197     fRetries = 0;
00198 
00199     // Release all resources
00200     //
00201     close();
00202     fPilotPath = QString::null;
00203 
00204     fPilotPath = dP;
00205     if (fPilotPath.isEmpty())
00206        fPilotPath = fTempDevice;
00207     if (fPilotPath.isEmpty())
00208         return;
00209 
00210     reset();
00211 }
00212 
00213 static inline void startOpenTimer(KPilotDeviceLink *dev, QTimer *&t)
00214 {
00215     if ( !t ){
00216         t = new QTimer(dev);
00217         QObject::connect(t, SIGNAL(timeout()),
00218             dev, SLOT(openDevice()));
00219     }
00220     t->start(1000, false);
00221 }
00222 
00223 void KPilotDeviceLink::reset()
00224 {
00225     FUNCTIONSETUP;
00226 
00227     messages=0;
00228     close();
00229 
00230     checkDevice();
00231 
00232     // Timer already deleted by close() call.
00233     startOpenTimer(this,fOpenTimer);
00234 
00235     fLinkStatus = WaitingForDevice;
00236 }
00237 
00238 void KPilotDeviceLink::checkDevice()
00239 {
00240     // If the device exists yet doesn't have the right
00241     // permissions, complain and then continue anyway.
00242     //
00243     QFileInfo fi(fPilotPath);
00244     if (fi.exists())
00245     {
00246         // If it exists, it ought to be RW already.
00247         //
00248         if (!(fi.isReadable() && fi.isWritable()))
00249         {
00250             emit logError(i18n("Pilot device %1 is not read-write.")
00251                 .arg(fPilotPath));
00252         }
00253     }
00254     else
00255     {
00256         // It doesn't exist, mention this in the log
00257         // (relevant as long as we use only one device type)
00258         //
00259         emit logError(i18n("Pilot device %1 does not exist. "
00260             "Probably it is a USB device and will appear during a HotSync.")
00261                 .arg(fPilotPath));
00262         messages |= (OpenMessage | OpenFailMessage);
00263     }
00264 }
00265 
00266 void KPilotDeviceLink::setTempDevice( const QString &d )
00267 {
00268     fTempDevice = d;
00269     KPilotDeviceLinkPrivate::self()->bindDevice( fTempDevice );
00270 }
00271 
00272 void KPilotDeviceLink::openDevice()
00273 {
00274     FUNCTIONSETUPL(2);
00275 
00276     // This transition (from Waiting to Found) can only be
00277     // taken once.
00278     //
00279     if (fLinkStatus == WaitingForDevice)
00280     {
00281         fLinkStatus = FoundDevice;
00282     }
00283 
00284     shouldPrint(OpenMessage,i18n("Trying to open device %1...")
00285         .arg(fPilotPath));
00286 
00287     if (open())
00288     {
00289         emit logMessage(i18n("Device link ready."));
00290     }
00291     else if (open(fTempDevice))
00292     {
00293         emit logMessage(i18n("Device link ready."));
00294     }
00295     else
00296     {
00297         shouldPrint(OpenFailMessage,i18n("Could not open device: %1 "
00298                 "(will retry)").
00299                 arg(fPilotPath));
00300 
00301         if (fLinkStatus != PilotLinkError)
00302         {
00303             startOpenTimer(this,fOpenTimer);
00304         }
00305     }
00306 }
00307 
00308 bool KPilotDeviceLink::open(QString device)
00309 {
00310     FUNCTIONSETUPL(2);
00311 
00312     int ret;
00313     int e = 0;
00314     QString msg;
00315 
00316     if (fCurrentPilotSocket != -1)
00317     {
00318         // See note in KPilotDeviceLink::close()
00319         pi_close(fCurrentPilotSocket);
00320 		::close(fCurrentPilotSocket);
00321     }
00322     fCurrentPilotSocket = (-1);
00323 
00324     if ( device.isEmpty() )
00325     {
00326         device = pilotPath();
00327     }
00328     if (device.isEmpty())
00329     {
00330         kdWarning() << k_funcinfo
00331             << ": No point in trying empty device."
00332             << endl;
00333 
00334         msg = i18n("The Pilot device is not configured yet.");
00335         e = 0;
00336         goto errInit;
00337     }
00338     fRealPilotPath = KStandardDirs::realPath ( device );
00339 
00340     if ( !KPilotDeviceLinkPrivate::self()->canBind( fRealPilotPath ) ) {
00341         msg = i18n("Already listening on that device");
00342         e=0;
00343         kdWarning() << k_funcinfo <<": Pilot Path " << pilotPath().latin1() << " already connected." << endl;
00344         goto errInit;
00345     }
00346 
00347 
00348     if (fPilotMasterSocket == -1)
00349     {
00350 #ifdef DEBUG
00351         DEBUGDAEMON << fname << ": Typing to open " << fRealPilotPath << endl;
00352 #endif
00353 
00354 #if PILOT_LINK_NUMBER < PILOT_LINK_0_10_0
00355         fPilotMasterSocket = pi_socket(PI_AF_SLP,
00356             PI_SOCK_STREAM, PI_PF_PADP);
00357 #else
00358         fPilotMasterSocket = pi_socket(PI_AF_PILOT,
00359             PI_SOCK_STREAM, PI_PF_DLP);
00360 #endif
00361 
00362         if (fPilotMasterSocket<1)
00363         {
00364             e = errno;
00365             msg = i18n("Cannot create socket for communicating "
00366                 "with the Pilot");
00367             goto errInit;
00368         }
00369 
00370 #ifdef DEBUG
00371         DEBUGDAEMON << fname
00372             << ": Got master " << fPilotMasterSocket << endl;
00373 #endif
00374 
00375         fLinkStatus = CreatedSocket;
00376     }
00377 
00378     Q_ASSERT(fLinkStatus == CreatedSocket);
00379 
00380 #ifdef DEBUG
00381     DEBUGDAEMON << fname << ": Binding to path " << fPilotPath << endl;
00382 #endif
00383 
00384 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
00385     struct pi_sockaddr addr;
00386 #if PILOT_LINK_NUMBER < PILOT_LINK_0_10_0
00387     addr.pi_family = PI_AF_SLP;
00388 #else
00389     addr.pi_family = PI_AF_PILOT;
00390 #endif
00391     strlcpy(addr.pi_device, QFile::encodeName(device),sizeof(addr.pi_device));
00392 
00393     ret = pi_bind(fPilotMasterSocket,
00394         (struct sockaddr *) &addr, sizeof(addr));
00395 #else
00396     ret = pi_bind(fPilotMasterSocket, QFile::encodeName(device));
00397 #endif
00398 
00399     if (ret >= 0)
00400     {
00401         fLinkStatus = DeviceOpen;
00402         if( fOpenTimer)
00403         fOpenTimer->stop();
00404 
00405         KPilotDeviceLinkPrivate::self()->bindDevice( fRealPilotPath );
00406         fSocketNotifier = new QSocketNotifier(fPilotMasterSocket,
00407             QSocketNotifier::Read, this);
00408         QObject::connect(fSocketNotifier, SIGNAL(activated(int)),
00409             this, SLOT(acceptDevice()));
00410         fSocketNotifierActive=true;
00411         
00412         if (fWorkaroundUSB)
00413         {
00414 #ifdef DEBUG
00415             DEBUGDAEMON << fname << ": Adding Z31 workaround." << endl;
00416 #endif
00417             // Special case for Zire 31, 72, Tungsten T5,
00418             // all of which may make a non-HotSync connection
00419             // to the PC. Must detect this and bail quickly.
00420             //
00421             fWorkaroundUSBTimer = new QTimer(this);
00422             connect(fWorkaroundUSBTimer,SIGNAL(timeout()),
00423                 this,SLOT(workaroundUSB()));
00424             fWorkaroundUSBTimer->start(5000,true);
00425         }
00426         
00427         return true;
00428     }
00429     else
00430     {
00431 #ifdef DEBUG
00432 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
00433         DEBUGDAEMON << fname
00434             << ": Tried "
00435             << addr.pi_device
00436             << " and got "
00437             << strerror(errno)
00438             << endl;
00439 #else
00440         DEBUGDAEMON << fname
00441             << ": Tried " << device << " and got " << strerror(errno) << endl;
00442 #endif
00443 #endif
00444 
00445         if (fRetries < 5)
00446         {
00447             return false;
00448         }
00449         e = errno;
00450         msg = i18n("Cannot open Pilot port \"%1\". ");
00451         if (fOpenTimer )
00452             fOpenTimer->stop();
00453 
00454         // goto errInit;
00455     }
00456 
00457 
00458 // We arrive here when some action for initializing the sockets
00459 // has gone wrong, and we need to log that and alert the user
00460 // that it has gone wrong.
00461 //
00462 //
00463 errInit:
00464     close();
00465 
00466     if (msg.find('%'))
00467     {
00468         if (fPilotPath.isEmpty())
00469         {
00470             msg = msg.arg(i18n("(empty)"));
00471         }
00472         else
00473         {
00474             msg = msg.arg(fPilotPath);
00475         }
00476     }
00477     switch (e)
00478     {
00479     case ENOENT:
00480         msg += i18n(" The port does not exist.");
00481         break;
00482     case ENODEV:
00483         msg += i18n(" These is no such device.");
00484         break;
00485     case EPERM:
00486         msg += i18n(" You do not have permission to open the "
00487             "Pilot device.");
00488         break;
00489     default:
00490         msg += i18n(" Check Pilot path and permissions.");
00491     }
00492 
00493     // OK, so we may have to deal with a translated
00494     // error message here. Big deal -- we have the line
00495     // number as well, right?
00496     //
00497     //
00498     kdError() << k_funcinfo << ": " << msg << endl;
00499     if (e)
00500     {
00501         kdError() << k_funcinfo
00502             << ": (" << strerror(e) << ")" << endl;
00503     }
00504 
00505     fLinkStatus = PilotLinkError;
00506     emit logError(msg);
00507     return false;
00508 }
00509 
00510 void KPilotDeviceLink::acceptDevice()
00511 {
00512     FUNCTIONSETUP;
00513 
00514     int ret;
00515 
00516     if (!fSocketNotifierActive)
00517     {
00518         if (!fAcceptedCount)
00519         {
00520         kdWarning() << k_funcinfo << ": Accidentally in acceptDevice()"
00521             << endl;
00522         }
00523         fAcceptedCount++;
00524         if (fAcceptedCount>10)
00525         {
00526             // Damn the torpedoes
00527             KPILOT_DELETE(fSocketNotifier);
00528         }
00529         return;
00530     }
00531 
00532     if (fSocketNotifier)
00533     {
00534         // fSocketNotifier->setEnabled(false);
00535         fSocketNotifierActive=false;
00536     }
00537 
00538 #ifdef DEBUG
00539     DEBUGDAEMON << fname
00540         << ": Found connection on device "<<pilotPath().latin1()<<endl;
00541     DEBUGDAEMON << fname
00542         << ": Current status "
00543         << statusString()
00544         << " and master " << fPilotMasterSocket << endl;
00545 #endif
00546 
00547     ret = pi_listen(fPilotMasterSocket, 1);
00548     if (ret == -1)
00549     {
00550         char *s = strerror(errno);
00551 
00552         kdWarning() << "pi_listen: " << s << endl;
00553 
00554         // Presumably, strerror() returns things in
00555         // local8Bit and not latin1.
00556         emit logError(i18n("Cannot listen on Pilot socket (%1)").
00557             arg(QString::fromLocal8Bit(s)));
00558 
00559         close();
00560         return;
00561     }
00562 
00563     KPILOT_DELETE(fWorkaroundUSBTimer);
00564 
00565     emit logProgress(QString::null,10);
00566 
00567     fCurrentPilotSocket = pi_accept(fPilotMasterSocket, 0, 0);
00568     if (fCurrentPilotSocket == -1)
00569     {
00570         char *s = strerror(errno);
00571 
00572         kdWarning() << "pi_accept: " << s << endl;
00573 
00574         emit logError(i18n("Cannot accept Pilot (%1)")
00575             .arg(QString::fromLocal8Bit(s)));
00576 
00577         fLinkStatus = PilotLinkError;
00578         close();
00579         return;
00580     }
00581 
00582     if ((fLinkStatus != DeviceOpen) || (fPilotMasterSocket == -1))
00583     {
00584         fLinkStatus = PilotLinkError;
00585         kdError() << k_funcinfo
00586             << ": Already connected or unable to connect!"
00587             << endl;
00588         emit logError(i18n("Cannot accept Pilot (%1)")
00589             .arg(i18n("already connected")));
00590         close();
00591         return;
00592     }
00593 
00594     emit logProgress(QString::null, 30);
00595 
00596         KPILOT_DELETE(fPilotSysInfo);
00597     fPilotSysInfo = new KPilotSysInfo;
00598     if (dlp_ReadSysInfo(fCurrentPilotSocket, fPilotSysInfo->sysInfo()) < 0)
00599     {
00600         emit logError(i18n("Unable to read system information from Pilot"));
00601         fLinkStatus=PilotLinkError;
00602         return;
00603     }
00604 #ifdef DEBUG
00605     else
00606     {
00607         DEBUGDAEMON << fname
00608             << ": RomVersion=" << fPilotSysInfo->getRomVersion()
00609             << " Locale=" << fPilotSysInfo->getLocale()
00610 #if PILOT_LINK_NUMBER < PILOT_LINK_0_10_0
00611             /* No prodID member */
00612 #else
00613             << " Product=" << fPilotSysInfo->getProductID()
00614 #endif
00615             << endl;
00616     }
00617 #endif
00618     fPilotSysInfo->boundsCheck();
00619 
00620     emit logProgress(QString::null, 60);
00621         KPILOT_DELETE(fPilotUser);
00622     fPilotUser = new KPilotUser;
00623 
00624     /* Ask the pilot who it is.  And see if it's who we think it is. */
00625 #ifdef DEBUG
00626     DEBUGDAEMON << fname << ": Reading user info @"
00627         << (long) fPilotUser << endl;
00628     DEBUGDAEMON << fname << ": Buffer @"
00629         << (long) fPilotUser->pilotUser() << endl;
00630 #endif
00631 
00632     dlp_ReadUserInfo(fCurrentPilotSocket, fPilotUser->pilotUser());
00633 
00634 #ifdef DEBUG
00635     DEBUGDAEMON << fname
00636         << ": Read user name " << fPilotUser->getUserName() << endl;
00637 #endif
00638 
00639     emit logProgress(i18n("Checking last PC..."), 90);
00640 
00641     /* Tell user (via Pilot) that we are starting things up */
00642     if ((ret=dlp_OpenConduit(fCurrentPilotSocket)) < 0)
00643     {
00644 #ifdef DEBUG
00645         DEBUGDAEMON << k_funcinfo
00646             << ": dlp_OpenConduit returned " << ret << endl;
00647 #endif
00648 
00649 #if 0
00650         fLinkStatus = SyncDone;
00651         emit logMessage(i18n
00652             ("Exiting on cancel. All data not restored."));
00653         return;
00654 #endif
00655         emit logError(i18n("Could not read user information from the Pilot. "
00656             "Perhaps you have a password set on the device?"));
00657     }
00658     fLinkStatus = AcceptedDevice;
00659 
00660 
00661     emit logProgress(QString::null, 100);
00662     emit deviceReady( this );
00663 }
00664 
00665 void KPilotDeviceLink::workaroundUSB()
00666 {
00667     FUNCTIONSETUP;
00668     
00669     Q_ASSERT((fLinkStatus == DeviceOpen) || (fLinkStatus == WorkaroundUSB));
00670     if (fLinkStatus == DeviceOpen)
00671     {
00672         reset();
00673     }
00674     fLinkStatus = WorkaroundUSB;
00675     
00676     if (!QFile::exists(fRealPilotPath))
00677     {
00678         // Fake connection has vanished again.
00679         // Resume polling for regular connection.
00680         startOpenTimer(this,fOpenTimer);
00681         return;
00682     }
00683     if (fOpenTimer)
00684     {
00685         fOpenTimer->stop();
00686     }
00687     KPILOT_DELETE(fWorkaroundUSBTimer);
00688     QTimer::singleShot(1000,this,SLOT(workaroundUSB()));
00689 }
00690 
00691 bool KPilotDeviceLink::tickle() const
00692 {
00693     // No FUNCTIONSETUP here because it may be called from
00694     // a separate thread.
00695     return pi_tickle(pilotSocket()) >= 0;
00696 }
00697 
00698 class TickleThread : public QThread
00699 {
00700 public:
00701     TickleThread(KPilotDeviceLink *d, bool *done, int timeout) :
00702         QThread(),
00703         fHandle(d),
00704         fDone(done),
00705         fTimeout(timeout)
00706     { };
00707     virtual ~TickleThread();
00708 
00709     virtual void run();
00710 
00711     static const int ChecksPerSecond = 5;
00712     static const int SecondsPerTickle = 5;
00713 
00714 private:
00715     KPilotDeviceLink *fHandle;
00716     bool *fDone;
00717     int fTimeout;
00718 } ;
00719 
00720 TickleThread::~TickleThread()
00721 {
00722 }
00723 
00724 void TickleThread::run()
00725 {
00726     FUNCTIONSETUP;
00727     int subseconds = ChecksPerSecond;
00728     int ticktock = SecondsPerTickle;
00729     int timeout = fTimeout;
00730 #ifdef DEBUG_CERR
00731     DEBUGDAEMON << fname << ": Running for " << timeout << " seconds." << endl;
00732     DEBUGDAEMON << fname << ": Done @" << (void *) fDone << endl;
00733 #endif
00734     while (!(*fDone))
00735     {
00736         QThread::msleep(1000/ChecksPerSecond);
00737         if (!(--subseconds))
00738         {
00739 #ifdef DEBUG_CERR
00740 // Don't dare use kdDebug() here, we're in a separate thread
00741             DEBUGDAEMON << fname << ": One second." << endl;
00742 #endif
00743             if (timeout)
00744             {
00745                 if (!(--timeout))
00746                 {
00747                     QApplication::postEvent(fHandle, new QEvent((QEvent::Type)(KPilotDeviceLink::TickleTimeoutEvent)));
00748                     break;
00749                 }
00750             }
00751             subseconds=ChecksPerSecond;
00752             if (!(--ticktock))
00753             {
00754 #ifdef DEBUG_CERR
00755                 DEBUGDAEMON << fname << ": Kietel kietel!." << endl;
00756 #endif
00757                 ticktock=SecondsPerTickle;
00758                 fHandle->tickle();
00759             }
00760         }
00761     }
00762 #ifdef DEBUG_CERR
00763     DEBUGDAEMON << fname << ": Finished." << endl;
00764 #endif
00765 }
00766 
00767 /*
00768 ** Deal with events, especially the ones used to signal a timeout
00769 ** in a tickle thread.
00770 */
00771 
00772 /* virtual */ bool KPilotDeviceLink::event(QEvent *e)
00773 {
00774     if (e->type() == TickleTimeoutEvent)
00775     {
00776         stopTickle();
00777         emit timeout();
00778         return true;
00779     }
00780     else    return QObject::event(e);
00781 }
00782 
00783 /*
00784 Start a tickle thread with the indicated timeout.
00785 */
00786 void KPilotDeviceLink::startTickle(unsigned int timeout)
00787 {
00788     FUNCTIONSETUP;
00789 
00790     Q_ASSERT(fTickleDone);
00791 
00792     /*
00793     ** We've told the thread to finish up, but it hasn't
00794     ** done so yet - so wait for it to do so, should be
00795     ** only 200ms at most.
00796     */
00797     if (fTickleDone && fTickleThread)
00798     {
00799         fTickleThread->wait();
00800         KPILOT_DELETE(fTickleThread);
00801     }
00802 
00803 #ifdef DEBUG
00804     DEBUGDAEMON << fname << ": Done @" << (void *) (&fTickleDone) << endl;
00805 #endif
00806     fTickleDone = false;
00807     fTickleThread = new TickleThread(this,&fTickleDone,timeout);
00808     fTickleThread->start();
00809 }
00810 
00811 void KPilotDeviceLink::stopTickle()
00812 {
00813     FUNCTIONSETUP;
00814     fTickleDone = true;
00815     if (fTickleThread)
00816     {
00817         fTickleThread->wait();
00818         KPILOT_DELETE(fTickleThread);
00819     }
00820 }
00821 
00822 
00823 int KPilotDeviceLink::installFiles(const QStringList & l, const bool deleteFiles)
00824 {
00825     FUNCTIONSETUP;
00826 
00827     QStringList::ConstIterator i;
00828     int k = 0;
00829     int n = 0;
00830 
00831     for (i = l.begin(); i != l.end(); ++i)
00832     {
00833         emit logProgress(QString::null,
00834             (int) ((100.0 / l.count()) * (float) n));
00835 
00836         if (installFile(*i, deleteFiles))
00837             k++;
00838         n++;
00839     }
00840     emit logProgress(QString::null, 100);
00841 
00842     return k;
00843 }
00844 
00845 bool KPilotDeviceLink::installFile(const QString & f, const bool deleteFile)
00846 {
00847     FUNCTIONSETUP;
00848 
00849 #ifdef DEBUG
00850     DEBUGDAEMON << fname << ": Installing file " << f << endl;
00851 #endif
00852 
00853     if (!QFile::exists(f))
00854         return false;
00855 
00856     char buffer[PATH_MAX];
00857     memset(buffer,0,PATH_MAX);
00858     strlcpy(buffer,QFile::encodeName(f),PATH_MAX);
00859     struct pi_file *pf =
00860         pi_file_open(buffer);
00861 
00862     if (!f)
00863     {
00864         kdWarning() << k_funcinfo
00865             << ": Cannot open file " << f << endl;
00866         emit logError(i18n
00867             ("<qt>Cannot install the file &quot;%1&quot;.</qt>").
00868             arg(f));
00869         return false;
00870     }
00871 
00872 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
00873     if (pi_file_install(pf, fCurrentPilotSocket, 0) < 0)
00874 #else
00875     if (pi_file_install(pf, fCurrentPilotSocket, 0, 0L) < 0)
00876 #endif
00877     {
00878         kdWarning() << k_funcinfo
00879             << ": Cannot pi_file_install " << f << endl;
00880         emit logError(i18n
00881             ("<qt>Cannot install the file &quot;%1&quot;.</qt>").
00882             arg(f));
00883         return false;
00884     }
00885 
00886     pi_file_close(pf);
00887     if (deleteFile) QFile::remove(f);
00888 
00889     return true;
00890 }
00891 
00892 
00893 void KPilotDeviceLink::addSyncLogEntry(const QString & entry, bool log)
00894 {
00895     FUNCTIONSETUP;
00896     if (entry.isEmpty()) return;
00897 
00898     QString t(entry);
00899 
00900 #if PILOT_LINK_NUMBER < PILOT_LINK_0_11_0
00901     t.append("X");
00902 #endif
00903 
00904     dlp_AddSyncLogEntry(fCurrentPilotSocket,
00905         const_cast<char *>((const char *)PilotAppCategory::codec()->fromUnicode(entry)));
00906     if (log)
00907     {
00908         emit logMessage(entry);
00909     }
00910 }
00911 
00912 int KPilotDeviceLink::openConduit()
00913 {
00914     return dlp_OpenConduit(fCurrentPilotSocket);
00915 }
00916 
00917 QString KPilotDeviceLink::statusString(LinkStatus l)
00918 {
00919     FUNCTIONSETUP;
00920     QString s = CSL1("KPilotDeviceLink=");
00921 
00922     switch (l)
00923     {
00924     case Init:
00925         s.append(CSL1("Init"));
00926         break;
00927     case WaitingForDevice:
00928         s.append(CSL1("WaitingForDevice"));
00929         break;
00930     case FoundDevice:
00931         s.append(CSL1("FoundDevice"));
00932         break;
00933     case CreatedSocket:
00934         s.append(CSL1("CreatedSocket"));
00935         break;
00936     case DeviceOpen:
00937         s.append(CSL1("DeviceOpen"));
00938         break;
00939     case AcceptedDevice:
00940         s.append(CSL1("AcceptedDevice"));
00941         break;
00942     case SyncDone:
00943         s.append(CSL1("SyncDone"));
00944         break;
00945     case PilotLinkError:
00946         s.append(CSL1("PilotLinkError"));
00947         break;
00948     case WorkaroundUSB:
00949         s.append(CSL1("WorkaroundUSB"));
00950         break;
00951     }
00952 
00953     return s;
00954 }
00955 
00956 QString KPilotDeviceLink::statusString() const
00957 {
00958     return statusString( status() );
00959 }
00960 
00961 void KPilotDeviceLink::endOfSync()
00962 {
00963     dlp_EndOfSync(pilotSocket(), 0);
00964     KPILOT_DELETE(fPilotSysInfo);
00965     KPILOT_DELETE(fPilotUser);
00966 }
00967 
00968 void KPilotDeviceLink::finishSync()
00969 {
00970     FUNCTIONSETUP ;
00971 
00972     getPilotUser()->setLastSyncPC((unsigned long) gethostid());
00973     getPilotUser()->setLastSyncDate(time(0));
00974 
00975     
00976 #ifdef DEBUG    
00977     DEBUGDAEMON << fname << ": Writing username " << getPilotUser()->getUserName() << endl;
00978 #endif
00979     dlp_WriteUserInfo(pilotSocket(),getPilotUser()->pilotUser());
00980     addSyncLogEntry(i18n("End of HotSync\n"));
00981     endOfSync();
00982 }
00983 
00984 int KPilotDeviceLink::getNextDatabase(int index,struct DBInfo *dbinfo)
00985 {
00986     FUNCTIONSETUP;
00987 
00988 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
00989     return dlp_ReadDBList(pilotSocket(),0,dlpDBListRAM,index,dbinfo);
00990 #else
00991     pi_buffer_t buf = { 0,0,0 };
00992     int r = dlp_ReadDBList(pilotSocket(),0,dlpDBListRAM,index,&buf);
00993     if (r >= 0)
00994     {
00995         memcpy(dbinfo,buf.data,sizeof(struct DBInfo));
00996     }
00997     return r;
00998 #endif
00999 }
01000 
01001 // Find a database with the given name. Info about the DB is stored into dbinfo (e.g. to be used later on with retrieveDatabase).
01002 int KPilotDeviceLink::findDatabase(const char *name, struct DBInfo *dbinfo,
01003     int index, long type, long creator)
01004 {
01005     FUNCTIONSETUP;
01006     return dlp_FindDBInfo(pilotSocket(), 0, index,
01007         const_cast<char *>(name), type, creator, dbinfo);
01008 }
01009 
01010 bool KPilotDeviceLink::retrieveDatabase(const QString &fullBackupName,
01011     DBInfo *info)
01012 {
01013     FUNCTIONSETUP;
01014 
01015 #ifdef DEBUG
01016     DEBUGDAEMON << fname << ": Writing DB <" << info->name << "> "
01017         << " to " << fullBackupName << endl;
01018 #endif
01019 
01020     struct pi_file *f;
01021     if (fullBackupName.isEmpty())
01022     {
01023         // Don't even bother trying to convert or retrieve.
01024         return false;
01025     }
01026     QCString encodedName = QFile::encodeName(fullBackupName);
01027     char filenameBuf[PATH_MAX];
01028     memset(filenameBuf,0,PATH_MAX);
01029     strlcpy(filenameBuf,(const char *)encodedName,PATH_MAX);
01030     f = pi_file_create(filenameBuf,info);
01031 
01032     if (f == 0)
01033     {
01034         kdWarning() << k_funcinfo
01035             << ": Failed, unable to create file" << endl;
01036         return false;
01037     }
01038 
01039 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
01040     if (pi_file_retrieve(f, pilotSocket(), 0) < 0)
01041 #else
01042     if (pi_file_retrieve(f, pilotSocket(), 0, 0L) < 0)
01043 #endif
01044     {
01045         kdWarning() << k_funcinfo
01046             << ": Failed, unable to back up database" << endl;
01047 
01048         pi_file_close(f);
01049         return false;
01050     }
01051 
01052     pi_file_close(f);
01053     return true;
01054 }
01055 
01056 
01057 QPtrList<DBInfo> KPilotDeviceLink::getDBList(int cardno, int flags)
01058 {
01059     bool cont=true;
01060     QPtrList<DBInfo>dbs;
01061     int index=0;
01062     while (cont)
01063     {
01064 #if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
01065         DBInfo*dbi=new DBInfo();
01066         if (dlp_ReadDBList(pilotSocket(), cardno, flags, index, dbi)<0)
01067         {
01068             KPILOT_DELETE(dbi);
01069             cont=false;
01070         }
01071         else
01072         {
01073             index=dbi->index+1;
01074             dbs.append(dbi);
01075         }
01076 #else
01077         pi_buffer_t buf = { 0,0,0 };
01078         pi_buffer_clear(&buf);
01079         // DBInfo*dbi=new DBInfo();
01080         if (dlp_ReadDBList(pilotSocket(), cardno, flags | dlpDBListMultiple, index, &buf)<0)
01081         {
01082             cont=false;
01083         }
01084         else
01085         {
01086             DBInfo *db_n = 0L;
01087             DBInfo *db_it = (DBInfo *)buf.data;
01088             int info_count = buf.used / sizeof(struct DBInfo);
01089 
01090             while(info_count>0)
01091             {
01092                 db_n = new DBInfo();
01093                 memcpy(db_n,db_it,sizeof(struct DBInfo));
01094                 ++db_it;
01095                 info_count--;
01096                 dbs.append(db_n);
01097             }
01098             if (db_n)
01099             {
01100                 index=db_n->index+1;
01101             }
01102         }
01103 #endif
01104     }
01105     return dbs;
01106 }
01107 
01108 KPilotCard *KPilotDeviceLink::getCardInfo(int card)
01109 {
01110     KPilotCard *cardinfo=new KPilotCard();
01111     if (dlp_ReadStorageInfo(pilotSocket(), card, cardinfo->cardInfo())<0)
01112     {
01113         kdWarning() << k_funcinfo << ": Could not get info for card "
01114             << card << endl;
01115 
01116         KPILOT_DELETE(cardinfo);
01117         return 0L;
01118     };
01119     return cardinfo;
01120 }
01121 
01122 QDateTime KPilotDeviceLink::getTime()
01123 {
01124     QDateTime time;
01125     time_t palmtime;
01126     if (dlp_GetSysDateTime(pilotSocket(), &palmtime))
01127     {
01128         time.setTime_t(palmtime);
01129     }
01130     return time;
01131 }
01132 
01133 bool KPilotDeviceLink::setTime(const time_t &pctime)
01134 {
01135 //  struct tm time_tm=writeTm(time);
01136 //  time_t pctime=mktime(&time_tm);
01137     return dlp_SetSysDateTime(pilotSocket(), pctime);
01138 }
01139 
01140 
01141 
01142 unsigned long KPilotDeviceLink::ROMversion() const
01143 {
01144     unsigned long rom;
01145     dlp_ReadFeature(pilotSocket(),
01146         makelong(const_cast<char *>("psys")), 1, &rom);
01147     return rom;
01148 }
01149 unsigned long KPilotDeviceLink::majorVersion() const
01150 {
01151     unsigned long rom=ROMversion();
01152     return (((rom >> 28) & 0xf) * 10)+ ((rom >> 24) & 0xf);
01153 }
01154 unsigned long KPilotDeviceLink::minorVersion() const
01155 {
01156     unsigned long int rom=ROMversion();
01157     return (((rom >> 20) & 0xf) * 10)+ ((rom >> 16) & 0xf);
01158 }
01159 
01160 /* static */ const int KPilotDeviceLink::messagesType=
01161     (int)OpenFailMessage ;
01162 
01163 void KPilotDeviceLink::shouldPrint(int m,const QString &s)
01164 {
01165     if (!(messages & m))
01166     {
01167         if (messagesType & m) { emit logError(s); }
01168         else { emit logMessage(s); }
01169         messages |= (m & messagesMask);
01170     }
01171 }
01172 
01173 bool operator < (const db & a, const db & b) {
01174     if (a.creator == b.creator)
01175     {
01176         if (a.type != b.type)
01177         {
01178             if (a.type == pi_mktag('a', 'p', 'p', 'l'))
01179                 return false;
01180             else
01181                 return true;
01182         }
01183     }
01184 
01185     return a.maxblock < b.maxblock;
01186 }
KDE Home | KDE Accessibility Home | Description of Access Keys