00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
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 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
00193
00194 void KPilotLink::startTickle(unsigned int timeout)
00195 {
00196 FUNCTIONSETUP;
00197
00198 Q_ASSERT(fTickleDone);
00199
00200
00201
00202
00203
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 int KPilotLink::openConduit()
00267 {
00268 return 0;
00269 }
00270
00271 int KPilotLink::pilotSocket() const
00272 {
00273 return -1;
00274 }
00275
00276
00277
00278
00279
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 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
00389
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
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
00443 startOpenTimer(this,fOpenTimer);
00444
00445 fLinkStatus = WaitingForDevice;
00446 }
00447
00448 void KPilotDeviceLink::checkDevice()
00449 {
00450
00451
00452
00453 QFileInfo fi(fPilotPath);
00454 if (fi.exists())
00455 {
00456
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
00467
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
00487
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
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
00610
00611
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
00638 }
00639
00640
00641
00642
00643
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
00677
00678
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
00710 KPILOT_DELETE(fSocketNotifier);
00711 }
00712 return;
00713 }
00714
00715 if (fSocketNotifier)
00716 {
00717
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
00738
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
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
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
00857
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 bool KPilotDeviceLink::tickle()
00870 {
00871
00872
00873 return pi_tickle(pilotSocket()) >= 0;
00874 }
00875
00876 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 "%1".</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 "%1".</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
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
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
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 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
01148 return 0;
01149 }
01150
01151
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
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 QString KPilotLocalLink::statusString() const
01197 {
01198 return fReady ? CSL1("Ready") : CSL1("Waiting") ;
01199 }
01200
01201 bool KPilotLocalLink::isConnected() const
01202 {
01203 return fReady;
01204 }
01205
01206 void KPilotLocalLink::reset( const QString &p )
01207 {
01208 FUNCTIONSETUP;
01209 fPath = p;
01210 reset();
01211 }
01212
01213 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 void KPilotLocalLink::close()
01233 {
01234 fReady = false;
01235 }
01236
01237 bool KPilotLocalLink::tickle()
01238 {
01239 return true;
01240 }
01241
01242 const KPilotCard *KPilotLocalLink::getCardInfo(int)
01243 {
01244 return 0;
01245 }
01246
01247 void KPilotLocalLink::endOfSync()
01248 {
01249 }
01250
01251 void KPilotLocalLink::finishSync()
01252 {
01253 }
01254
01255 int KPilotLocalLink::openConduit()
01256 {
01257 FUNCTIONSETUP;
01258 return 0;
01259 }
01260
01261
01262 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 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 void KPilotLocalLink::addSyncLogEntryImpl(QString const &s)
01327 {
01328 FUNCTIONSETUP;
01329 DEBUGLIBRARY << fname << ": " << s << endl ;
01330 }
01331
01332 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
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 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 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 PilotDatabase *KPilotLocalLink::database( const QString &name )
01417 {
01418 FUNCTIONSETUP;
01419 return new PilotLocalDatabase( fPath, name );
01420 }
01421
01422
01423
01424 void KPilotLocalLink::ready()
01425 {
01426 if (fReady)
01427 {
01428 emit deviceReady(this);
01429 }
01430 }
01431