kpilot/lib

kpilotdevicelink.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-2007 Adriaan de Groot <groot@kde.org>
00006 ** Copyright (C) 2007 Jason 'vanRijn' Kasper <vR@movingparts.net>
00007 **
00008 */
00009 
00010 /*
00011 ** This program is free software; you can redistribute it and/or modify
00012 ** it under the terms of the GNU Lesser General Public License as published by
00013 ** the Free Software Foundation; either version 2.1 of the License, or
00014 ** (at your option) any later version.
00015 **
00016 ** This program is distributed in the hope that it will be useful,
00017 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 ** GNU Lesser General Public License for more details.
00020 **
00021 ** You should have received a copy of the GNU Lesser General Public License
00022 ** along with this program in a file called COPYING; if not, write to
00023 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00024 ** MA 02110-1301, USA.
00025 */
00026 
00027 /*
00028 ** Bug reports and questions can be sent to kde-pim@kde.org
00029 */
00030 
00031 #include "options.h"
00032 
00033 
00034 
00035 #include <sys/stat.h>
00036 #include <sys/types.h>
00037 #include <stdio.h>
00038 #include <unistd.h>
00039 #include <fcntl.h>
00040 #include <errno.h>
00041 
00042 #include <iostream>
00043 
00044 #include <pi-source.h>
00045 #include <pi-socket.h>
00046 #include <pi-dlp.h>
00047 #include <pi-file.h>
00048 #include <pi-buffer.h>
00049 
00050 #include <qdir.h>
00051 #include <qtimer.h>
00052 #include <qdatetime.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.h"
00068 #include "kpilotdevicelink.moc"
00069 
00070 
00071 // singleton helper class
00072 class DeviceMap
00073 {
00074 public:
00075     static DeviceMap *self()
00076     {
00077         if (!mThis) mThis = new DeviceMap();
00078         return mThis;
00079     }
00080 
00081     bool canBind( const QString &device )
00082     {
00083         showList();
00084         return !mBoundDevices.contains( device );
00085     }
00086 
00087     void bindDevice( const QString &device )
00088     {
00089         mBoundDevices.append( device );
00090         showList();
00091     }
00092 
00093     void unbindDevice( const QString &device )
00094     {
00095         mBoundDevices.remove( device );
00096         showList();
00097     }
00098 
00099 protected:
00100     DeviceMap() {}
00101     ~DeviceMap() {}
00102 
00103     QStringList mBoundDevices;
00104     static DeviceMap *mThis;
00105 
00106 private:
00107     inline void showList() const
00108     {
00109         if ( !(mBoundDevices.count() > 0) ) return;
00110         FUNCTIONSETUPL(3);
00111         DEBUGKPILOT << fname << ": Bound devices: ["
00112             << ((mBoundDevices.count() > 0) ?
00113             mBoundDevices.join(CSL1(", ")) : CSL1("<none>")) 
00114             << "]" << endl;
00115     }
00116 } ;
00117 
00118 DeviceMap *DeviceMap::mThis = 0L;
00119 
00120 class Messages
00121 {
00122 public:
00123     Messages(KPilotDeviceLink *parent) :
00124         fDeviceLink(parent)
00125     {
00126         reset();
00127     }
00128 
00129     void reset()
00130     {
00131         messages = 0;
00132         messagesMask = ~messageIsError; // Never block errors
00133     }
00134 
00135     void block(unsigned int m, bool force=false)
00136     {
00137         if (force)
00138         {
00139             // Force blocking this message, even if it's an error msg.
00140             messages |= m;
00141         }
00142         else
00143         {
00144             messages |= (m & messagesMask);
00145         }
00146     }
00147 
00153     enum {
00154         OpenMessage=1, 
00155         OpenFailMessage=2 
00156     } ;
00157     int messages;
00158     int messagesMask;
00159     static const int messageIsError = 0;
00160 
00166     bool shouldPrint(int msgid)
00167     {
00168         if (!(messages & msgid))
00169         {
00170             block(msgid);
00171             return true;
00172         }
00173         else
00174         {
00175             return false;
00176         }
00177     }
00178     
00179 protected:
00180     KPilotDeviceLink *fDeviceLink;
00181 } ;
00182 
00183 class DeviceCommEvent : public QCustomEvent
00184 {
00185 public:
00186     DeviceCommEvent ( DeviceCustomEvents type, QString msg = QString::null, int progress = 0)
00187         : QCustomEvent( type ),
00188         fMessage( msg ),
00189         fProgress( progress ),
00190         fPilotSocket(-1) {}
00191     QString message() const
00192     {
00193         return fMessage;
00194     }
00195     int progress()
00196     {
00197         return fProgress;
00198     }
00199 
00200     inline void setCurrentSocket(int i) { fPilotSocket = i; }
00201 
00202     inline int currentSocket() { return fPilotSocket; }
00203 private:
00204     QString fMessage;
00205     int fProgress;
00209     int fPilotSocket;
00210 };
00211 
00212 
00218 class DeviceCommThread : public QThread
00219 {
00220 friend class KPilotDeviceLink;
00221 public:
00222     DeviceCommThread(KPilotDeviceLink *d) :
00223         QThread(),
00224         fDone(true),
00225         fHandle(d),
00226         fPilotSocket(-1),
00227         fTempSocket(-1)
00228     { };
00229     virtual ~DeviceCommThread();
00230 
00231     virtual void run();
00232 
00233     static const int SecondsBetweenPoll = 1;
00234 
00235     void setDone(bool b) 
00236     { 
00237         FUNCTIONSETUP;
00238         fDone = b; 
00239     }
00240 
00241 private:
00242     volatile bool fDone;
00243 
00244     KPilotDeviceLink *fHandle;
00245     inline KPilotDeviceLink *link() 
00246     {
00247         if (fHandle) 
00248         {
00249             return fHandle;
00250         }
00251         else
00252         {
00253             FUNCTIONSETUP;
00254             WARNINGKPILOT << "Link asked for, but either I'm "
00255                 << "done or I don't have a valid handle.  "
00256                 << "Shutting down comm thread." << endl;
00257             QThread::exit();
00258             return 0;
00259         }
00260     }
00261 
00265     int fPilotSocket;
00266     int fTempSocket;
00267 
00268 protected:
00275     bool openDevice();
00276 
00277     void close();
00278 
00279 protected:
00284     bool open( const QString &device = QString::null );
00285     
00286 private:
00287     inline QString errorMessage(int e) 
00288     {
00289         switch (e)
00290         {
00291         case ENOENT:
00292             return i18n(" The port does not exist.");
00293             break;
00294         case ENODEV:
00295             return i18n(" There is no such device.");
00296             break;
00297         case EPERM:
00298             return i18n(" You do not have permission to open the "
00299                 "Pilot device.");
00300             break;
00301         default:
00302             return i18n(" Check Pilot path and permissions.");
00303         }
00304     }
00305 
00306 } ;
00307 
00308 DeviceCommThread::~DeviceCommThread()
00309 {
00310     FUNCTIONSETUPL(2);
00311     close();
00312 }
00313 
00314 
00315 bool DeviceCommThread::openDevice()
00316 {
00317     FUNCTIONSETUPL(2);
00318 
00319     bool deviceOpened = false;
00320 
00321     // This transition (from Waiting to Found) can only be
00322     // taken once.
00323     //
00324     if (link()->fLinkStatus == WaitingForDevice)
00325     {
00326         link()->fLinkStatus = FoundDevice;
00327     }
00328 
00329     if (link()->fMessages->shouldPrint(Messages::OpenMessage))
00330     {
00331         QApplication::postEvent(link(), new DeviceCommEvent(EventLogMessage,
00332             i18n("Trying to open device %1...")
00333             .arg(link()->fPilotPath)));
00334     }
00335 
00336     // if we're not supposed to be done, try to open the main pilot
00337     // path...
00338     if (!fDone && link()->fPilotPath.length() > 0)
00339     {
00340         DEBUGKPILOT << fname << ": Opening main pilot path: [" 
00341             << link()->fPilotPath << "]." << endl;
00342         deviceOpened = open( link()->fPilotPath ); 
00343     }
00344 
00345     // only try the temp device if our earlier attempt didn't work and the temp
00346     // device is different than the main device, and it's a non-empty
00347     // string
00348     bool tryTemp = !deviceOpened && 
00349             (link()->fTempDevice.length() > 0) &&
00350             (link()->fPilotPath != link()->fTempDevice) ;
00351 
00352     // if we're not supposed to be done, and we should try the temp
00353     // device, try the temp device...
00354     if (!fDone && tryTemp)
00355     {
00356         DEBUGKPILOT << fname << ": Couldn't open main pilot path. "
00357             << "Now trying temp device: [" 
00358             << link()->fTempDevice << "]." << endl;
00359         deviceOpened = open( link()->fTempDevice );
00360     }
00361 
00362     return deviceOpened;
00363 }
00364 
00365 bool DeviceCommThread::open(const QString &device)
00366 {
00367     FUNCTIONSETUPL(2);
00368 
00369     int ret;
00370     int e = 0;
00371     QString msg;
00372 
00373     link()->fRealPilotPath = KStandardDirs::realFilePath(device.isEmpty() ? link()->fPilotPath : device );
00374 
00375     if ( !DeviceMap::self()->canBind( link()->fRealPilotPath ) ) {
00376         msg = i18n("Already listening on that device");
00377         
00378         WARNINGKPILOT << "Pilot Path: ["
00379             << link()->fRealPilotPath << "] already connected." << endl;
00380         WARNINGKPILOT << msg << endl;
00381 
00382         link()->fLinkStatus = PilotLinkError;
00383 
00384         QApplication::postEvent(link(),
00385             new DeviceCommEvent(EventLogError, msg));
00386 
00387         return false;
00388     }
00389 
00390 
00391     DEBUGKPILOT << fname << ": Trying to create socket." << endl;
00392 
00393     fTempSocket = pi_socket(PI_AF_PILOT, PI_SOCK_STREAM, PI_PF_DLP);
00394 
00395     if (fTempSocket < 0)
00396     {
00397         e = errno;
00398         msg = i18n("Cannot create socket for communicating "
00399             "with the Pilot (%1)").arg(errorMessage(e));
00400         WARNINGKPILOT << msg << endl;
00401         WARNINGKPILOT << "(" << strerror(e) << ")" << endl;
00402     
00403         link()->fLinkStatus = PilotLinkError;
00404         
00405         QApplication::postEvent(link(),
00406             new DeviceCommEvent(EventLogError, msg));
00407     
00408         return false;
00409     }
00410 
00411     DEBUGKPILOT << fname << ": Got socket: [" << fTempSocket << "]" << endl;
00412 
00413     link()->fLinkStatus = CreatedSocket;
00414 
00415     DEBUGKPILOT << fname << ": Binding to path: [" 
00416         << link()->fRealPilotPath << "]" << endl;
00417 
00418     ret = pi_bind(fTempSocket, QFile::encodeName(link()->fRealPilotPath));
00419 
00420     if (ret < 0)
00421     {
00422         DEBUGKPILOT << fname
00423             << ": pi_bind error: ["
00424             << strerror(errno) << "]" << endl;
00425 
00426         e = errno;
00427         msg = i18n("Cannot open Pilot port \"%1\". ").arg(link()->fRealPilotPath);
00428         
00429         WARNINGKPILOT << msg << endl;
00430         WARNINGKPILOT << "(" << strerror(e) << ")" << endl;
00431     
00432         link()->fLinkStatus = PilotLinkError;
00433         
00434         if (link()->fMessages->shouldPrint(Messages::OpenFailMessage))
00435         {
00436             QApplication::postEvent(link(),
00437                 new DeviceCommEvent(EventLogError, msg));
00438         }
00439 
00440         return false;
00441     }
00442 
00443     link()->fLinkStatus = DeviceOpen;
00444     DeviceMap::self()->bindDevice( link()->fRealPilotPath );
00445 
00446     DEBUGKPILOT << fname
00447         << ": Current status: ["
00448         << link()->statusString()
00449         << "] and socket: [" << fTempSocket << "]" << endl;
00450 
00451     ret = pi_listen(fTempSocket, 1);
00452     if (ret < 0)
00453     {
00454         char *s = strerror(errno);
00455 
00456         WARNINGKPILOT << "pi_listen returned: [" << s << "]" << endl;
00457 
00458         // Presumably, strerror() returns things in
00459         // local8Bit and not latin1.
00460         QApplication::postEvent(link(),
00461             new DeviceCommEvent(EventLogError,
00462                 i18n("Cannot listen on Pilot socket (%1)").
00463                 arg(QString::fromLocal8Bit(s)))
00464             );
00465 
00466         return false;
00467     }
00468 
00469     QApplication::postEvent(link(),
00470         new DeviceCommEvent(EventLogProgress, QString::null, 10));
00471 
00472     DEBUGKPILOT << fname <<
00473         ": Listening to pilot. Now trying accept..." << endl;
00474 
00475     int timeout=20;
00476     if (link()->fWorkaroundUSB)
00477         timeout=10;
00478 
00479     fPilotSocket = pi_accept_to(fTempSocket, 0, 0, timeout);
00480 
00481     if (fPilotSocket < 0)
00482     {
00483         char *s = strerror(errno);
00484 
00485         WARNINGKPILOT << "pi_accept returned: [" << s << "]" << endl;
00486 
00487         QApplication::postEvent(link(),
00488             new DeviceCommEvent(EventLogError, i18n("Cannot accept Pilot (%1)")
00489             .arg(QString::fromLocal8Bit(s))));
00490 
00491         link()->fLinkStatus = PilotLinkError;
00492         return false;
00493     }
00494 
00495     DEBUGKPILOT << fname << ": Link accept done." << endl;
00496 
00497     if ((link()->fLinkStatus != DeviceOpen) || (fPilotSocket == -1))
00498     {
00499         link()->fLinkStatus = PilotLinkError;
00500         WARNINGKPILOT << "Already connected or unable to connect!" << endl;
00501 
00502         QApplication::postEvent(link(),
00503             new DeviceCommEvent(EventLogError, i18n("Cannot accept Pilot (%1)")
00504             .arg(i18n("already connected"))));
00505 
00506         return false;
00507     }
00508 
00509     QApplication::postEvent(link(),
00510         new DeviceCommEvent(EventLogProgress, QString::null, 30));
00511 
00512     DEBUGKPILOT << fname << ": doing dlp_ReadSysInfo..." << endl;
00513 
00514     struct SysInfo sys_info;
00515     if (dlp_ReadSysInfo(fPilotSocket, &sys_info) < 0)
00516     {
00517         QApplication::postEvent(link(),
00518             new DeviceCommEvent(EventLogError,
00519             i18n("Unable to read system information from Pilot")));
00520 
00521         link()->fLinkStatus=PilotLinkError;
00522         return false;
00523     }
00524     else
00525     {
00526         DEBUGKPILOT << fname << ": dlp_ReadSysInfo successful..." << endl;
00527 
00528             KPILOT_DELETE(link()->fPilotSysInfo);
00529         link()->fPilotSysInfo = new KPilotSysInfo(&sys_info);
00530         DEBUGKPILOT << fname
00531             << ": RomVersion: [" << link()->fPilotSysInfo->getRomVersion()
00532             << "] Locale: [" << link()->fPilotSysInfo->getLocale()
00533             << "] Product: [" << link()->fPilotSysInfo->getProductID()
00534             << "]" << endl;
00535     }
00536 
00537     QApplication::postEvent(link(),
00538         new DeviceCommEvent(EventLogProgress, QString::null, 60));
00539 
00540         KPILOT_DELETE(link()->fPilotUser);
00541     link()->fPilotUser = new KPilotUser;
00542 
00543     DEBUGKPILOT << fname << ": doing dlp_ReadUserInfo..." << endl;
00544 
00545     /* Ask the pilot who it is.  And see if it's who we think it is. */
00546     dlp_ReadUserInfo(fPilotSocket, link()->fPilotUser->data());
00547 
00548     QString n = link()->getPilotUser().name();
00549     DEBUGKPILOT << fname
00550         << ": Read user name: [" << n << "]" << endl;
00551 
00552     QApplication::postEvent(link(),
00553         new DeviceCommEvent(EventLogProgress, i18n("Checking last PC..."), 90));
00554 
00555     /* Tell user (via Pilot) that we are starting things up */
00556     if ((ret=dlp_OpenConduit(fPilotSocket)) < 0)
00557     {
00558         DEBUGKPILOT << fname
00559             << ": dlp_OpenConduit returned: [" << ret << "]" << endl;
00560 
00561         QApplication::postEvent(link(),
00562             new DeviceCommEvent(EventLogError,
00563             i18n("Could not read user information from the Pilot. "
00564             "Perhaps you have a password set on the device?")));
00565 
00566     }
00567     link()->fLinkStatus = AcceptedDevice;
00568 
00569     QApplication::postEvent(link(),
00570         new DeviceCommEvent(EventLogProgress, QString::null, 100));
00571 
00572     return true;
00573 }
00574 
00575 void DeviceCommThread::close()
00576 {
00577     FUNCTIONSETUP;
00578 
00579     pi_close(fTempSocket);
00580 
00581     if (fPilotSocket != -1)
00582     {
00583         DEBUGKPILOT << fname
00584             << ": device comm thread closing socket: ["
00585             << fPilotSocket << "]" << endl;
00586 
00587         pi_close(fPilotSocket);
00588     }
00589     fPilotSocket = (-1);
00590 
00591     DeviceMap::self()->unbindDevice( link()->fRealPilotPath );
00592 }
00593 
00594 
00595 void DeviceCommThread::run()
00596 {
00597     FUNCTIONSETUP;
00598     int sleepBetweenPoll = SecondsBetweenPoll;
00599     fDone = false;
00600 
00601     DEBUGKPILOT << fname << ": Polling every: ["
00602         << sleepBetweenPoll << "] seconds." << endl;
00603 
00604     while (!fDone)
00605     {
00606         openDevice();
00607 
00608         if (link()->fLinkStatus == AcceptedDevice)
00609         {
00610             DeviceCommEvent * ev = new DeviceCommEvent(EventDeviceReady);
00611             ev->setCurrentSocket(fPilotSocket);
00612             QApplication::postEvent(link(), ev);
00613 
00614             break;
00615         }
00616         else
00617         {
00618             if (link()->fMessages->shouldPrint(Messages::OpenFailMessage))
00619             {
00620                 QApplication::postEvent(link(), 
00621                     new DeviceCommEvent(EventLogMessage, 
00622                         i18n("Could not open device: %1 (will retry)")
00623                         .arg(link()->fPilotPath)));
00624             }
00625             close();
00626 
00627             // sleep before trying again
00628             QThread::sleep(sleepBetweenPoll);
00629         }
00630     }
00631 
00632     DEBUGKPILOT << fname << ": comm thread waiting to be done..." << endl;
00633 
00634     // keep the thread alive until we're supposed to be done
00635     while (!fDone)
00636     {
00637         QThread::sleep(sleepBetweenPoll);
00638     }
00639 
00640     close();
00641     // now sleep one last bit to make sure the pthread inside
00642     // pilot-link (potentially, if it's libusb) is done before we exit
00643     QThread::sleep(1);
00644 
00645     DEBUGKPILOT << fname << ": comm thread now done..." << endl;
00646 }
00647 
00648 
00649 
00650 
00651 KPilotDeviceLink::KPilotDeviceLink(QObject * parent, const char *name, const QString &tempDevice) :
00652     KPilotLink(parent, name),
00653     fLinkStatus(Init),
00654     fWorkaroundUSB(false),
00655     fPilotSocket(-1),
00656     fTempDevice(tempDevice),
00657     fMessages(new Messages(this)),
00658     fDeviceCommThread(0L)
00659 {
00660     FUNCTIONSETUP;
00661 
00662     DEBUGKPILOT << fname
00663         << ": Pilot-link version: [" << PILOT_LINK_NUMBER
00664         << "]" << endl;
00665 }
00666 
00667 KPilotDeviceLink::~KPilotDeviceLink()
00668 {
00669     FUNCTIONSETUP;
00670     close();
00671     KPILOT_DELETE(fPilotSysInfo);
00672     KPILOT_DELETE(fPilotUser);
00673     KPILOT_DELETE(fMessages);
00674 }
00675 
00676 /* virtual */ bool KPilotDeviceLink::isConnected() const
00677 {
00678      return fLinkStatus == AcceptedDevice;
00679 }
00680 
00681 void KPilotDeviceLink::customEvent(QCustomEvent *e)
00682 {
00683     FUNCTIONSETUP;
00684 
00685     if ((int)e->type() == EventDeviceReady)
00686     {
00687         DeviceCommEvent* t = dynamic_cast<DeviceCommEvent*>(e);
00688         if (t)
00689         {
00690             fPilotSocket = t->currentSocket();
00691             emit deviceReady( this );
00692         }
00693         else
00694         {
00695             DEBUGKPILOT << fname
00696                 << ": unable to cast event: [" << e << "]" << endl;
00697         }
00698     }
00699     else if ((int)e->type() == EventLogMessage)
00700     {
00701         DeviceCommEvent* t = dynamic_cast<DeviceCommEvent*>(e);
00702         if (t)
00703         {
00704             emit logMessage(t->message());
00705         }
00706         else
00707         {
00708             DEBUGKPILOT << fname
00709                 << ": unable to cast event: [" << e << "]" << endl;
00710         }
00711     }
00712     else if ((int)e->type() == EventLogError)
00713     {
00714         DeviceCommEvent* t = dynamic_cast<DeviceCommEvent*>(e);
00715         if (t)
00716         {
00717             emit logError(t->message());
00718         }
00719         else
00720         {
00721             DEBUGKPILOT << fname
00722                 << ": unable to cast event: [" << e << "]" << endl;
00723         }
00724     }
00725     else if ((int)e->type() == EventLogProgress)
00726     {
00727         DeviceCommEvent* t = dynamic_cast<DeviceCommEvent*>(e);
00728         if (t)
00729         {
00730             emit logProgress(t->message(), t->progress());
00731         }
00732         else
00733         {
00734             DEBUGKPILOT << fname
00735                 << ": unable to cast event: [" << e << "]" << endl;
00736         }
00737     }
00738     else
00739     {
00740         KPilotLink::customEvent(e);
00741     }
00742 }
00743 
00744 void KPilotDeviceLink::stopCommThread()
00745 {
00746     FUNCTIONSETUP;
00747     if (fDeviceCommThread)
00748     {
00749         fDeviceCommThread->setDone(true);
00750 
00751         // try to wait for our thread to finish, but don't
00752         // block the main thread forever
00753         if (fDeviceCommThread->running()) 
00754         {
00755             DEBUGKPILOT << fname
00756                 << ": comm thread still running. "
00757                 << "waiting for it to complete." << endl;
00758             bool done = fDeviceCommThread->wait(30000);
00759             if (!done)
00760             {
00761                 DEBUGKPILOT << fname
00762                     << ": comm thread still running "
00763                     << "after wait(). "
00764                     << "going to have to terminate it."
00765                     << endl;
00766                 // not normally to be done, but we must make sure
00767                 // that this device doesn't come back alive
00768                 fDeviceCommThread->terminate();
00769                 fDeviceCommThread->wait();
00770             }
00771         }
00772 
00773         fDeviceCommThread->close();
00774 
00775         KPILOT_DELETE(fDeviceCommThread);
00776     }
00777 }
00778 
00779 void KPilotDeviceLink::close()
00780 {
00781     FUNCTIONSETUP;
00782 
00783     stopCommThread();
00784 
00785     fPilotSocket = (-1);
00786 }
00787 
00788 void KPilotDeviceLink::reset(const QString & dP)
00789 {
00790     FUNCTIONSETUP;
00791 
00792     fLinkStatus = Init;
00793 
00794     // Release all resources
00795     //
00796     close();
00797     fPilotPath = QString::null;
00798 
00799     fPilotPath = dP;
00800     if (fPilotPath.isEmpty())
00801        fPilotPath = fTempDevice;
00802     if (fPilotPath.isEmpty())
00803         return;
00804 
00805     reset();
00806 }
00807 
00808 void KPilotDeviceLink::startCommThread()
00809 {
00810     FUNCTIONSETUP;
00811 
00812     stopCommThread();
00813 
00814     if (fTempDevice.isEmpty() && pilotPath().isEmpty())
00815     {
00816         WARNINGKPILOT << "No point in trying empty device."
00817             << endl;
00818 
00819         QString msg = i18n("The Pilot device is not configured yet.");
00820         WARNINGKPILOT << msg << endl;
00821 
00822 
00823         fLinkStatus = PilotLinkError;
00824         
00825         emit logError(msg);
00826         return;
00827     }
00828 
00829     fDeviceCommThread = new DeviceCommThread(this);
00830     fDeviceCommThread->start();
00831 }
00832 
00833 
00834 void KPilotDeviceLink::reset()
00835 {
00836     FUNCTIONSETUP;
00837 
00838     fMessages->reset();
00839     close();
00840 
00841     checkDevice();
00842 
00843     fLinkStatus = WaitingForDevice;
00844 
00845     startCommThread();
00846 }
00847 
00848 void KPilotDeviceLink::checkDevice()
00849 {
00850     // If the device exists yet doesn't have the right
00851     // permissions, complain and then continue anyway.
00852     //
00853     QFileInfo fi(fPilotPath);
00854     if (fi.exists())
00855     {
00856         // If it exists, it ought to be RW already.
00857         //
00858         if (!(fi.isReadable() && fi.isWritable()))
00859         {
00860             emit logError(i18n("Pilot device %1 is not read-write.")
00861                 .arg(fPilotPath));
00862         }
00863     }
00864     else
00865     {
00866         // It doesn't exist, mention this in the log
00867         // (relevant as long as we use only one device type)
00868         //
00869         emit logError(i18n("Pilot device %1 does not exist. "
00870             "Probably it is a USB device and will appear during a HotSync.")
00871                 .arg(fPilotPath));
00872         // Suppress all normal and error messages about opening the device.
00873         fMessages->block(Messages::OpenMessage | Messages::OpenFailMessage, true);
00874     }
00875 }
00876 
00877 void KPilotDeviceLink::setTempDevice( const QString &d )
00878 {
00879     fTempDevice = d;
00880     DeviceMap::self()->bindDevice( fTempDevice );
00881 }
00882 
00883 
00884 /* virtual */ bool KPilotDeviceLink::tickle()
00885 {
00886     // No FUNCTIONSETUP here because it may be called from
00887     // a separate thread.
00888     return pi_tickle(pilotSocket()) >= 0;
00889 }
00890 
00891 /* virtual */ void KPilotDeviceLink::addSyncLogEntryImpl( const QString &entry )
00892 {
00893     dlp_AddSyncLogEntry(fPilotSocket,
00894         const_cast<char *>((const char *)Pilot::toPilot(entry)));
00895 }
00896 
00897 bool KPilotDeviceLink::installFile(const QString & f, const bool deleteFile)
00898 {
00899     FUNCTIONSETUP;
00900 
00901     DEBUGKPILOT << fname << ": Installing file " << f << endl;
00902 
00903     if (!QFile::exists(f))
00904         return false;
00905 
00906     char buffer[PATH_MAX];
00907     memset(buffer,0,PATH_MAX);
00908     strlcpy(buffer,QFile::encodeName(f),PATH_MAX);
00909     struct pi_file *pf =
00910         pi_file_open(buffer);
00911 
00912     if (!f)
00913     {
00914         WARNINGKPILOT << "Cannot open file " << f << endl;
00915         emit logError(i18n
00916             ("<qt>Cannot install the file &quot;%1&quot;.</qt>").
00917             arg(f));
00918         return false;
00919     }
00920 
00921     if (pi_file_install(pf, fPilotSocket, 0, 0L) < 0)
00922     {
00923         WARNINGKPILOT << "Cannot pi_file_install " << f << endl;
00924         emit logError(i18n
00925             ("<qt>Cannot install the file &quot;%1&quot;.</qt>").
00926             arg(f));
00927         return false;
00928     }
00929 
00930     pi_file_close(pf);
00931     if (deleteFile) QFile::remove(f);
00932 
00933     return true;
00934 }
00935 
00936 
00937 int KPilotDeviceLink::openConduit()
00938 {
00939     return dlp_OpenConduit(fPilotSocket);
00940 }
00941 
00942 QString KPilotDeviceLink::statusString(LinkStatus l)
00943 {
00944     QString s = CSL1("KPilotDeviceLink=");
00945 
00946     switch (l)
00947     {
00948     case Init:
00949         s.append(CSL1("Init"));
00950         break;
00951     case WaitingForDevice:
00952         s.append(CSL1("WaitingForDevice"));
00953         break;
00954     case FoundDevice:
00955         s.append(CSL1("FoundDevice"));
00956         break;
00957     case CreatedSocket:
00958         s.append(CSL1("CreatedSocket"));
00959         break;
00960     case DeviceOpen:
00961         s.append(CSL1("DeviceOpen"));
00962         break;
00963     case AcceptedDevice:
00964         s.append(CSL1("AcceptedDevice"));
00965         break;
00966     case SyncDone:
00967         s.append(CSL1("SyncDone"));
00968         break;
00969     case PilotLinkError:
00970         s.append(CSL1("PilotLinkError"));
00971         break;
00972     case WorkaroundUSB:
00973         s.append(CSL1("WorkaroundUSB"));
00974         break;
00975     }
00976 
00977     return s;
00978 }
00979 
00980 QString KPilotDeviceLink::statusString() const
00981 {
00982     return statusString( status() );
00983 }
00984 
00985 void KPilotDeviceLink::endSync( EndOfSyncFlags f )
00986 {
00987     FUNCTIONSETUP;
00988 
00989     if ( UpdateUserInfo == f )
00990     {
00991         getPilotUser().setLastSyncPC((unsigned long) gethostid());
00992         getPilotUser().setLastSyncDate(time(0));
00993 
00994         DEBUGKPILOT << fname << ": Writing username " << getPilotUser().name() << endl;
00995 
00996         dlp_WriteUserInfo(pilotSocket(),getPilotUser().data());
00997         addSyncLogEntry(i18n("End of HotSync\n"));
00998     }
00999     dlp_EndOfSync(pilotSocket(), 0);
01000     KPILOT_DELETE(fPilotSysInfo);
01001     KPILOT_DELETE(fPilotUser);
01002 }
01003 
01004 
01005 int KPilotDeviceLink::getNextDatabase(int index,struct DBInfo *dbinfo)
01006 {
01007     FUNCTIONSETUP;
01008 
01009     pi_buffer_t buf = { 0,0,0 };
01010     int r = dlp_ReadDBList(pilotSocket(),0,dlpDBListRAM,index,&buf);
01011     if (r >= 0)
01012     {
01013         memcpy(dbinfo,buf.data,sizeof(struct DBInfo));
01014     }
01015     return r;
01016 }
01017 
01018 // Find a database with the given name. Info about the DB is stored into dbinfo (e.g. to be used later on with retrieveDatabase).
01019 int KPilotDeviceLink::findDatabase(const char *name, struct DBInfo *dbinfo,
01020     int index, unsigned long type, unsigned long creator)
01021 {
01022     FUNCTIONSETUP;
01023     return dlp_FindDBInfo(pilotSocket(), 0, index,
01024         const_cast<char *>(name), type, creator, dbinfo);
01025 }
01026 
01027 bool KPilotDeviceLink::retrieveDatabase(const QString &fullBackupName,  DBInfo *info)
01028 {
01029     FUNCTIONSETUP;
01030 
01031 
01032     if (fullBackupName.isEmpty() || !info)
01033     {
01034         // Don't even bother trying to convert or retrieve.
01035         return false;
01036     }
01037 
01038     DEBUGKPILOT << fname << ": Writing DB <" << info->name << "> "
01039         << " to " << fullBackupName << endl;
01040 
01041     QCString encodedName = QFile::encodeName(fullBackupName);
01042     struct pi_file *f = pi_file_create(encodedName,info);
01043 
01044     if (!f)
01045     {
01046         WARNINGKPILOT << "Failed, unable to create file" << endl;
01047         return false;
01048     }
01049 
01050     if (pi_file_retrieve(f, pilotSocket(), 0, 0L) < 0)
01051     {
01052         WARNINGKPILOT << "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 KPilotLink::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         WARNINGKPILOT << "Could not get info for card "
01102             << card << endl;
01103 
01104         KPILOT_DELETE(cardinfo);
01105         return 0L;
01106     };
01107     return cardinfo;
01108 }
01109 
01110 PilotDatabase *KPilotDeviceLink::database( const QString &name )
01111 {
01112     return new PilotSerialDatabase( this, name );
01113 }
01114 
01115 PilotDatabase *KPilotDeviceLink::database( const DBInfo *info )
01116 {
01117     return new PilotSerialDatabase( this, info );
01118 }
01119 
KDE Home | KDE Accessibility Home | Description of Access Keys