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 static const char *kpilotlink_id = "$Id: kpilotlink.cc,v 1.26.4.6 2003/03/10 23:29:25 adridg Exp $";
00028
00029 #include "options.h"
00030
00031 #include <pi-source.h>
00032 #include <pi-socket.h>
00033 #include <pi-dlp.h>
00034 #include <pi-file.h>
00035 #include <pi-version.h>
00036
00037 #ifndef PILOT_LINK_VERSION
00038 #error "You need at least pilot-link version 0.9.5"
00039 #endif
00040
00041 #define PILOT_LINK_NUMBER ((100*PILOT_LINK_VERSION) + \
00042 PILOT_LINK_MAJOR)
00043
00044 #include <sys/stat.h>
00045 #include <sys/types.h>
00046 #include <stdio.h>
00047 #include <unistd.h>
00048 #include <fcntl.h>
00049 #include <errno.h>
00050
00051 #include <iostream>
00052
00053 #include <qdir.h>
00054 #include <qtimer.h>
00055 #include <qdatetime.h>
00056 #include <qsocketnotifier.h>
00057
00058 #include <kconfig.h>
00059 #include <kmessagebox.h>
00060
00061 #include "pilotUser.h"
00062
00063 #include "kpilotlink.moc"
00064
00065
00066
00067 QDateTime readTm(const struct tm &t)
00068 {
00069 QDateTime dt;
00070 dt.setDate(QDate(1900 + t.tm_year, t.tm_mon + 1, t.tm_mday));
00071 dt.setTime(QTime(t.tm_hour, t.tm_min, t.tm_sec));
00072 return dt;
00073 }
00074
00075 struct tm writeTm(const QDateTime &dt)
00076 {
00077 struct tm t;
00078 t.tm_wday = 0;
00079 t.tm_yday = 0;
00080 t.tm_isdst = 0;
00081
00082 t.tm_year = dt.date().year() - 1900;
00083 t.tm_mon = dt.date().month() - 1;
00084 t.tm_mday = dt.date().day();
00085 t.tm_hour = dt.time().hour();
00086 t.tm_min = dt.time().minute();
00087 t.tm_sec = dt.time().second();
00088 return t;
00089 }
00090
00091
00092 KPilotDeviceLink *KPilotDeviceLink::fDeviceLink = 0L;
00093
00094 KPilotDeviceLink::KPilotDeviceLink(QObject * parent, const char *name) :
00095 QObject(parent, name),
00096 fStatus(Init),
00097 fPilotPath(QString::null),
00098 fDeviceType(None),
00099 fRetries(0),
00100 fOpenTimer(0L),
00101 fSocketNotifier(0L),
00102 fSocketNotifierActive(false),
00103 fPilotMasterSocket(-1),
00104 fCurrentPilotSocket(-1)
00105 {
00106 FUNCTIONSETUP;
00107
00108 #ifdef DEBUG
00109 DEBUGDAEMON << fname
00110 << ": Pilot-link version " << PILOT_LINK_NUMBER
00111 << endl;
00112 #endif
00113
00114 ASSERT(fDeviceLink == 0L);
00115 fDeviceLink = this;
00116 messagesMask=0xffffffff;
00117
00118 (void) kpilotlink_id;
00119 }
00120
00121 KPilotDeviceLink::~KPilotDeviceLink()
00122 {
00123 FUNCTIONSETUP;
00124 close();
00125 fDeviceLink = 0L;
00126 }
00127
00128 KPilotDeviceLink *KPilotDeviceLink::init(QObject * parent, const char *name)
00129 {
00130 FUNCTIONSETUP;
00131
00132 ASSERT(!fDeviceLink);
00133
00134 return new KPilotDeviceLink(parent, name);
00135 }
00136
00137 void KPilotDeviceLink::close()
00138 {
00139 FUNCTIONSETUP;
00140
00141 KPILOT_DELETE(fOpenTimer);
00142 KPILOT_DELETE(fSocketNotifier);
00143 fSocketNotifierActive=false;
00144 #ifdef DEBUG
00145 DEBUGDAEMON << fname
00146 << ": Closing sockets "
00147 << fCurrentPilotSocket
00148 << " and "
00149 << fPilotMasterSocket
00150 << endl;
00151 #endif
00152 if (fCurrentPilotSocket != -1)
00153 {
00154 pi_close(fCurrentPilotSocket);
00155
00156
00157 ::close(fCurrentPilotSocket);
00158 }
00159 if (fPilotMasterSocket != -1)
00160 {
00161 pi_close(fPilotMasterSocket);
00162 ::close(fPilotMasterSocket);
00163 }
00164 fPilotMasterSocket = (-1);
00165 fCurrentPilotSocket = (-1);
00166 }
00167
00168 void KPilotDeviceLink::reset(DeviceType t, const QString & dP)
00169 {
00170 FUNCTIONSETUP;
00171
00172 fStatus = Init;
00173 fRetries = 0;
00174
00175
00176
00177
00178 close();
00179 fPilotPath = QString::null;
00180
00181 fDeviceType = t;
00182 if (t == None)
00183 return;
00184 fDeviceType=OldStyleUSB;
00185
00186 fPilotPath = dP;
00187 if (fPilotPath.isEmpty())
00188 return;
00189
00190 reset();
00191 }
00192
00193 void KPilotDeviceLink::reset()
00194 {
00195 FUNCTIONSETUP;
00196
00197 messages=0;
00198 close();
00199
00200 checkDevice();
00201
00202
00203 fOpenTimer = new QTimer(this);
00204 QObject::connect(fOpenTimer, SIGNAL(timeout()),
00205 this, SLOT(openDevice()));
00206 fOpenTimer->start(1000, false);
00207
00208 fStatus = WaitingForDevice;
00209 }
00210
00211 void KPilotDeviceLink::checkDevice()
00212 {
00213
00214
00215
00216 QFileInfo fi(fPilotPath);
00217 if (fi.exists())
00218 {
00219
00220
00221 if (!(fi.isReadable() && fi.isWritable()))
00222 {
00223 emit logError(i18n("Pilot device %1 is not read-write.")
00224 .arg(fPilotPath));
00225 }
00226 }
00227 else
00228 {
00229
00230
00231
00232 emit logError(i18n("Pilot device %1 doesn't exist. "
00233 "Assuming the device uses DevFS.")
00234 .arg(fPilotPath));
00235 }
00236 }
00237
00238
00239 void KPilotDeviceLink::openDevice()
00240 {
00241 FUNCTIONSETUPL(2);
00242
00243
00244
00245
00246 if (fStatus == WaitingForDevice)
00247 {
00248 fStatus = FoundDevice;
00249 }
00250
00251 shouldPrint(OpenMessage,i18n("Trying to open device..."));
00252
00253 if (open())
00254 {
00255 emit logMessage(i18n("Device link ready."));
00256 }
00257 else
00258 {
00259 shouldPrint(OpenFailMessage,i18n("Could not open device: %1 "
00260 "(will retry)").
00261 arg(fPilotPath));
00262
00263 if (fStatus != PilotLinkError)
00264 {
00265 fOpenTimer->start(1000, false);
00266 }
00267 }
00268 }
00269
00270 bool KPilotDeviceLink::open()
00271 {
00272 FUNCTIONSETUPL(2);
00273
00274 struct pi_sockaddr addr;
00275 int ret;
00276 int e = 0;
00277 QString msg;
00278
00279 if (fCurrentPilotSocket != -1)
00280 {
00281
00282 pi_close(fCurrentPilotSocket);
00283 ::close(fCurrentPilotSocket);
00284 }
00285 fCurrentPilotSocket = (-1);
00286
00287 if (fPilotMasterSocket == -1)
00288 {
00289 if (fPilotPath.isEmpty())
00290 {
00291 kdWarning() << k_funcinfo
00292 << ": No point in trying empty device."
00293 << endl;
00294
00295 msg = i18n("The Pilot device is not configured yet.");
00296 e = 0;
00297 goto errInit;
00298 }
00299 #ifdef DEBUG
00300 DEBUGDAEMON << fname << ": Typing to open " << fPilotPath << endl;
00301 #endif
00302
00303 #if PILOT_LINK_NUMBER < 10
00304 fPilotMasterSocket = pi_socket(PI_AF_SLP,
00305 PI_SOCK_STREAM, PI_PF_PADP);
00306 #else
00307 fPilotMasterSocket = pi_socket(PI_AF_PILOT,
00308 PI_SOCK_STREAM, PI_PF_DLP);
00309 #endif
00310
00311 if (fPilotMasterSocket<1)
00312 {
00313 e = errno;
00314 msg = i18n("Cannot create socket for communicating "
00315 "with the Pilot");
00316 goto errInit;
00317 }
00318
00319 #ifdef DEBUG
00320 DEBUGDAEMON << fname
00321 << ": Got master " << fPilotMasterSocket << endl;
00322 #endif
00323
00324 fStatus = CreatedSocket;
00325 }
00326
00327 ASSERT(fStatus == CreatedSocket);
00328
00329 #ifdef DEBUG
00330 DEBUGDAEMON << fname << ": Binding to path " << fPilotPath << endl;
00331 #endif
00332
00333 #if PILOT_LINK_NUMBER < 10
00334 addr.pi_family = PI_AF_SLP;
00335 #else
00336 addr.pi_family = PI_AF_PILOT;
00337 #endif
00338 strncpy(addr.pi_device, QFile::encodeName(fPilotPath),sizeof(addr.pi_device));
00339
00340
00341 ret = pi_bind(fPilotMasterSocket,
00342 (struct sockaddr *) &addr, sizeof(addr));
00343
00344 if (ret >= 0)
00345 {
00346 fStatus = DeviceOpen;
00347 fOpenTimer->stop();
00348
00349 fSocketNotifier = new QSocketNotifier(fPilotMasterSocket,
00350 QSocketNotifier::Read, this);
00351 QObject::connect(fSocketNotifier, SIGNAL(activated(int)),
00352 this, SLOT(acceptDevice()));
00353 fSocketNotifierActive=true;
00354 return true;
00355 }
00356 else
00357 {
00358 #ifdef DEBUG
00359 DEBUGDAEMON << fname
00360 << ": Tried "
00361 << addr.pi_device
00362 << " and got "
00363 << strerror(errno)
00364 << endl;
00365 #endif
00366
00367 if (isTransient() && (fRetries < 5))
00368 {
00369 return false;
00370 }
00371 e = errno;
00372 msg = i18n("Cannot open Pilot port \"%1\". ");
00373
00374 fOpenTimer->stop();
00375
00376
00377 }
00378
00379
00380
00381
00382
00383
00384
00385 errInit:
00386 close();
00387
00388 if (msg.find('%'))
00389 {
00390 if (fPilotPath.isEmpty())
00391 {
00392 msg = msg.arg(i18n("(empty)"));
00393 }
00394 else
00395 {
00396 msg = msg.arg(fPilotPath);
00397 }
00398 }
00399 switch (e)
00400 {
00401 case ENOENT:
00402 msg += i18n(" The port does not exist.");
00403 break;
00404 case ENODEV:
00405 msg += i18n(" These is no such device.");
00406 break;
00407 case EPERM:
00408 msg += i18n(" You don't have permission to open the "
00409 "Pilot device.");
00410 break;
00411 default:
00412 msg += i18n(" Check Pilot path and permissions.");
00413 }
00414
00415
00416
00417
00418
00419
00420 kdError() << k_funcinfo << ": " << msg << endl;
00421 if (e)
00422 {
00423 kdError() << k_funcinfo
00424 << ": (" << strerror(e) << ")" << endl;
00425 }
00426
00427 fStatus = PilotLinkError;
00428 emit logError(msg);
00429 return false;
00430 }
00431
00432 void KPilotDeviceLink::acceptDevice()
00433 {
00434 FUNCTIONSETUP;
00435
00436 int ret;
00437
00438 if (!fSocketNotifierActive)
00439 {
00440 kdWarning() << k_funcinfo << ": Accidentally in acceptDevice()"
00441 << endl;
00442 return;
00443 }
00444
00445 if (fSocketNotifier)
00446 {
00447
00448 fSocketNotifierActive=false;
00449 }
00450
00451 #ifdef DEBUG
00452 DEBUGDAEMON << fname
00453 << ": Current status "
00454 << statusString()
00455 << " and master " << fPilotMasterSocket << endl;
00456 #endif
00457
00458 ret = pi_listen(fPilotMasterSocket, 1);
00459 if (ret == -1)
00460 {
00461 char *s = strerror(errno);
00462
00463 kdWarning() << "pi_listen: " << s << endl;
00464
00465
00466
00467 emit logError(i18n("Can't listen on Pilot socket (%1)").
00468 arg(QString::fromLocal8Bit(s)));
00469
00470 close();
00471 return;
00472 }
00473
00474 emit logProgress(QString::null,10);
00475
00476 fCurrentPilotSocket = pi_accept(fPilotMasterSocket, 0, 0);
00477 if (fCurrentPilotSocket == -1)
00478 {
00479 char *s = strerror(errno);
00480
00481 kdWarning() << "pi_accept: " << s << endl;
00482
00483 emit logError(i18n("Can't accept Pilot (%1)")
00484 .arg(QString::fromLocal8Bit(s)));
00485
00486 fStatus = PilotLinkError;
00487 close();
00488 return;
00489 }
00490
00491 if ((fStatus != DeviceOpen) || (fPilotMasterSocket == -1))
00492 {
00493 fStatus = PilotLinkError;
00494 kdError() << k_funcinfo
00495 << ": Already connected or unable to connect!"
00496 << endl;
00497 emit logError(TODO_I18N("Can't accept Pilot (%1)")
00498 .arg(TODO_I18N("already connected")));
00499 close();
00500 return;
00501 }
00502
00503 emit logProgress(QString::null, 30);
00504
00505 struct SysInfo sys_info;
00506 if (dlp_ReadSysInfo(fCurrentPilotSocket,&sys_info) < 0)
00507 {
00508 emit logError(i18n("Unable to read system information from Pilot"));
00509 fStatus=PilotLinkError;
00510 return;
00511 }
00512 #ifdef DEBUG
00513 else
00514 {
00515 DEBUGDAEMON << fname
00516 << ": RomVersion=" << sys_info.romVersion
00517 << " Locale=" << sys_info.locale
00518 #if PILOT_LINK_NUMBER < 10
00519
00520 #else
00521 << " Product=" << sys_info.prodID
00522 #endif
00523 << endl;
00524 }
00525 #endif
00526
00527 emit logProgress(QString::null, 60);
00528 fPilotUser = new KPilotUser;
00529
00530
00531 #ifdef DEBUG
00532 DEBUGDAEMON << fname << ": Reading user info @"
00533 << (int) fPilotUser << endl;
00534 DEBUGDAEMON << fname << ": Buffer @"
00535 << (int) fPilotUser->pilotUser() << endl;
00536 #endif
00537
00538 dlp_ReadUserInfo(fCurrentPilotSocket, fPilotUser->pilotUser());
00539 fPilotUser->boundsCheck();
00540
00541 #ifdef DEBUG
00542 DEBUGDAEMON << fname
00543 << ": Read user name " << fPilotUser->getUserName() << endl;
00544 #endif
00545
00546 emit logProgress(i18n("Checking last PC..."), 90);
00547
00548
00549 if ((ret=dlp_OpenConduit(fCurrentPilotSocket)) < 0)
00550 {
00551 DEBUGDAEMON << k_funcinfo
00552 << ": dlp_OpenConduit returned " << ret << endl;
00553
00554 #if 0
00555 fStatus = SyncDone;
00556 emit logMessage(i18n
00557 ("Exiting on cancel. All data not restored."));
00558 return;
00559 #endif
00560 emit logError(i18n("Could not read user information from the Pilot. "
00561 "Perhaps you have a password set on the device?"));
00562 }
00563 fStatus = AcceptedDevice;
00564
00565
00566 emit logProgress(QString::null, 100);
00567 emit deviceReady();
00568 }
00569
00570 void KPilotDeviceLink::tickle() const
00571 {
00572 FUNCTIONSETUP;
00573 pi_tickle(pilotSocket());
00574 }
00575
00576
00577 int KPilotDeviceLink::installFiles(const QStringList & l, const bool deleteFiles)
00578 {
00579 FUNCTIONSETUP;
00580
00581 QStringList::ConstIterator i;
00582 int k = 0;
00583 int n = 0;
00584
00585 for (i = l.begin(); i != l.end(); ++i)
00586 {
00587 emit logProgress(QString::null,
00588 (int) ((100.0 / l.count()) * (float) n));
00589
00590 if (installFile(*i, deleteFiles))
00591 k++;
00592 n++;
00593 }
00594 emit logProgress(QString::null, 100);
00595
00596 return k;
00597 }
00598
00599 bool KPilotDeviceLink::installFile(const QString & f, const bool deleteFile)
00600 {
00601 FUNCTIONSETUP;
00602
00603 #ifdef DEBUG
00604 DEBUGDAEMON << fname << ": Installing file " << f << endl;
00605 #endif
00606
00607 if (!QFile::exists(f))
00608 return false;
00609
00610 struct pi_file *pf =
00611 pi_file_open(const_cast < char *>
00612 ((const char *) QFile::encodeName(f)));
00613
00614 if (!f)
00615 {
00616 kdWarning() << k_funcinfo
00617 << ": Can't open file " << f << endl;
00618 emit logError(i18n
00619 ("<qt>Can't install the file "%1".</qt>").
00620 arg(f));
00621 return false;
00622 }
00623
00624 if (pi_file_install(pf, fCurrentPilotSocket, 0) < 0)
00625 {
00626 kdWarning() << k_funcinfo
00627 << ": Can't pi_file_install " << f << endl;
00628 emit logError(i18n
00629 ("<qt>Can't install the file "%1".</qt>").
00630 arg(f));
00631 return false;
00632 }
00633
00634 pi_file_close(pf);
00635 if (deleteFile) QFile::remove(f);
00636
00637 return true;
00638 }
00639
00640
00641 void KPilotDeviceLink::addSyncLogEntry(const QString & entry, bool log)
00642 {
00643 FUNCTIONSETUP;
00644
00645 QString t(entry);
00646
00647 #if (PILOT_LINK_VERSION * 1000 + PILOT_LINK_MAJOR * 10 + PILOT_LINK_MINOR) < 110
00648 t.append("X");
00649 #endif
00650
00651 dlp_AddSyncLogEntry(fCurrentPilotSocket,
00652 const_cast < char *>(t.latin1()));
00653 if (log)
00654 {
00655 emit logMessage(entry);
00656 }
00657 }
00658
00659 int KPilotDeviceLink::openConduit()
00660 {
00661 return dlp_OpenConduit(fCurrentPilotSocket);
00662 }
00663
00664 QString KPilotDeviceLink::deviceTypeString(int i) const
00665 {
00666 FUNCTIONSETUP;
00667 switch (i)
00668 {
00669 case None:
00670 return QString::fromLatin1("None");
00671 case Serial:
00672 return QString::fromLatin1("Serial");
00673 case OldStyleUSB:
00674 return QString::fromLatin1("OldStyleUSB");
00675 case DevFSUSB:
00676 return QString::fromLatin1("DevFSUSB");
00677 default:
00678 return QString::fromLatin1("<unknown>");
00679 }
00680 }
00681
00682 QString KPilotDeviceLink::statusString() const
00683 {
00684 FUNCTIONSETUP;
00685 QString s = QString::fromLatin1("KPilotDeviceLink=");
00686
00687
00688 switch (fStatus)
00689 {
00690 case Init:
00691 s.append(QString::fromLatin1("Init"));
00692 break;
00693 case WaitingForDevice:
00694 s.append(QString::fromLatin1("WaitingForDevice"));
00695 break;
00696 case FoundDevice:
00697 s.append(QString::fromLatin1("FoundDevice"));
00698 break;
00699 case CreatedSocket:
00700 s.append(QString::fromLatin1("CreatedSocket"));
00701 break;
00702 case DeviceOpen:
00703 s.append(QString::fromLatin1("DeviceOpen"));
00704 break;
00705 case AcceptedDevice:
00706 s.append(QString::fromLatin1("AcceptedDevice"));
00707 break;
00708 case SyncDone:
00709 s.append(QString::fromLatin1("SyncDone"));
00710 break;
00711 case PilotLinkError:
00712 s.append(QString::fromLatin1("PilotLinkError"));
00713 break;
00714 }
00715
00716 return s;
00717 }
00718
00719
00720 void KPilotDeviceLink::finishSync()
00721 {
00722 FUNCTIONSETUP ;
00723
00724 getPilotUser()->setLastSyncPC((unsigned long) gethostid());
00725 getPilotUser()->setLastSyncDate(time(0));
00726
00727 dlp_WriteUserInfo(pilotSocket(),getPilotUser()->pilotUser());
00728 addSyncLogEntry(i18n("End of HotSync\n"));
00729 dlp_EndOfSync(pilotSocket(), 0);
00730 }
00731
00732 int KPilotDeviceLink::getNextDatabase(int index,struct DBInfo *dbinfo)
00733 {
00734 FUNCTIONSETUP;
00735
00736 return dlp_ReadDBList(pilotSocket(),0,dlpDBListRAM,index,dbinfo);
00737 }
00738
00739
00740 int KPilotDeviceLink::findDatabase(const char *name, struct DBInfo *dbinfo,
00741 int index, long type, long creator)
00742 {
00743 FUNCTIONSETUP;
00744 return dlp_FindDBInfo(pilotSocket(), 0, index,
00745 const_cast<char *>(name), type, creator, dbinfo);
00746 }
00747
00748 bool KPilotDeviceLink::retrieveDatabase(const QString &fullBackupName,
00749 DBInfo *info)
00750 {
00751 FUNCTIONSETUP;
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761 struct pi_file *f;
00762 f = pi_file_create(const_cast < char *>
00763 ((const char *) (QFile::encodeName(fullBackupName))),
00764 info);
00765
00766 if (f == 0)
00767 {
00768 kdWarning() << k_funcinfo
00769 << ": Failed, unable to create file" << endl;
00770 return false;
00771 }
00772
00773 if (pi_file_retrieve(f, pilotSocket(), 0) < 0)
00774 {
00775 kdWarning() << k_funcinfo
00776 << ": Failed, unable to back up database" << endl;
00777
00778 pi_file_close(f);
00779 return false;
00780 }
00781
00782 pi_file_close(f);
00783 return true;
00784 }
00785
00786
00787 QDateTime KPilotDeviceLink::getTime()
00788 {
00789 QDateTime time;
00790 time_t palmtime;
00791 if (dlp_GetSysDateTime(pilotSocket(), &palmtime))
00792 {
00793 time.setTime_t(palmtime);
00794 }
00795 return time;
00796 }
00797
00798 bool KPilotDeviceLink::setTime(const time_t &pctime)
00799 {
00800
00801
00802 return dlp_SetSysDateTime(pilotSocket(), pctime);
00803 }
00804
00805
00806
00807 unsigned long KPilotDeviceLink::ROMversion() const
00808 {
00809 unsigned long rom;
00810 dlp_ReadFeature(pilotSocket(),
00811 makelong(const_cast<char *>("psys")), 1, &rom);
00812 return rom;
00813 }
00814 unsigned long KPilotDeviceLink::majorVersion() const
00815 {
00816 unsigned long rom=ROMversion();
00817 return (((rom >> 28) & 0xf) * 10)+ ((rom >> 24) & 0xf);
00818 }
00819 unsigned long KPilotDeviceLink::minorVersion() const
00820 {
00821 unsigned long int rom=ROMversion();
00822 return (((rom >> 20) & 0xf) * 10)+ ((rom >> 16) & 0xf);
00823 }
00824
00825 const int KPilotDeviceLink::messagesType=
00826 (int)OpenFailMessage ;
00827
00828 void KPilotDeviceLink::shouldPrint(int m,const QString &s)
00829 {
00830 if (!(messages & m))
00831 {
00832 if (messagesType & m) { emit logError(s); }
00833 else { emit logMessage(s); }
00834 messages |= (m & messagesMask);
00835 }
00836 }
00837
00838 bool operator < (const db & a, const db & b) {
00839 if (a.creator == b.creator)
00840 {
00841 if (a.type != b.type)
00842 {
00843 if (a.type == pi_mktag('a', 'p', 'p', 'l'))
00844 return false;
00845 else
00846 return true;
00847 }
00848 }
00849
00850 return a.maxblock < b.maxblock;
00851 }