|
|
|
/* KPilot
|
|
|
|
**
|
|
|
|
** Copyright (C) 1998-2001 by Dan Pilone
|
|
|
|
** Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
|
|
|
|
** Copyright (C) 2006-2007 Adriaan de Groot <groot@kde.org>
|
|
|
|
** Copyright (C) 2007 Jason 'vanRijn' Kasper <vR@movingparts.net>
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
** This program is free software; you can redistribute it and/or modify
|
|
|
|
** it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
** the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
** (at your option) any later version.
|
|
|
|
**
|
|
|
|
** This program is distributed in the hope that it will be useful,
|
|
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
** GNU Lesser General Public License for more details.
|
|
|
|
**
|
|
|
|
** You should have received a copy of the GNU Lesser General Public License
|
|
|
|
** along with this program in a file called COPYING; if not, write to
|
|
|
|
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
** MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Bug reports and questions can be sent to kde-pim@kde.org
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "options.h"
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <pi-source.h>
|
|
|
|
#include <pi-socket.h>
|
|
|
|
#include <pi-dlp.h>
|
|
|
|
#include <pi-file.h>
|
|
|
|
#include <pi-buffer.h>
|
|
|
|
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
#include <tqthread.h>
|
|
|
|
#include <tqsocketnotifier.h>
|
|
|
|
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kurl.h>
|
|
|
|
#include <kio/netaccess.h>
|
|
|
|
|
|
|
|
#include "pilotUser.h"
|
|
|
|
#include "pilotSysInfo.h"
|
|
|
|
#include "pilotCard.h"
|
|
|
|
#include "pilotSerialDatabase.h"
|
|
|
|
#include "pilotLocalDatabase.h"
|
|
|
|
|
|
|
|
#include "kpilotlink.h"
|
|
|
|
#include "kpilotdevicelinkPrivate.moc"
|
|
|
|
#include "kpilotdevicelink.moc"
|
|
|
|
|
|
|
|
|
|
|
|
DeviceMap *DeviceMap::mThis = 0L;
|
|
|
|
|
|
|
|
|
|
|
|
static inline void startOpenTimer(DeviceCommThread *dev, TQTimer *&t)
|
|
|
|
{
|
|
|
|
if ( !t)
|
|
|
|
{
|
|
|
|
t = new TQTimer(dev);
|
|
|
|
TQObject::connect(t, TQT_SIGNAL(timeout()), dev, TQT_SLOT(openDevice()));
|
|
|
|
}
|
|
|
|
// just a single-shot timer. we'll know when to start it again...
|
|
|
|
t->start(1000, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
DeviceCommThread::DeviceCommThread(KPilotDeviceLink *d) :
|
|
|
|
TQThread(),
|
|
|
|
fDone(true),
|
|
|
|
fHandle(d),
|
|
|
|
fOpenTimer(0L),
|
|
|
|
fSocketNotifier(0L),
|
|
|
|
fSocketNotifierActive(false),
|
|
|
|
fWorkaroundUSBTimer(0L),
|
|
|
|
fPilotSocket(-1),
|
|
|
|
fTempSocket(-1),
|
|
|
|
fAcceptedCount(0)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DeviceCommThread::~DeviceCommThread()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUPL(2);
|
|
|
|
close();
|
|
|
|
KPILOT_DELETE(fWorkaroundUSBTimer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceCommThread::close()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUPL(2);
|
|
|
|
|
|
|
|
KPILOT_DELETE(fWorkaroundUSBTimer);
|
|
|
|
KPILOT_DELETE(fOpenTimer);
|
|
|
|
KPILOT_DELETE(fSocketNotifier);
|
|
|
|
fSocketNotifierActive=false;
|
|
|
|
|
|
|
|
if (fTempSocket != -1)
|
|
|
|
{
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": device comm thread closing socket: ["
|
|
|
|
<< fTempSocket << "]" << endl;
|
|
|
|
|
|
|
|
pi_close(fTempSocket);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fPilotSocket != -1)
|
|
|
|
{
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": device comm thread closing socket: ["
|
|
|
|
<< fPilotSocket << "]" << endl;
|
|
|
|
|
|
|
|
pi_close(fPilotSocket);
|
|
|
|
}
|
|
|
|
|
|
|
|
fTempSocket = (-1);
|
|
|
|
fPilotSocket = (-1);
|
|
|
|
|
|
|
|
DeviceMap::self()->unbindDevice(link()->fRealPilotPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceCommThread::reset()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
if (link()->fMessages->shouldPrint(Messages::OpenFailMessage))
|
|
|
|
{
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogMessage,
|
|
|
|
i18n("Could not open device: %1 (will retry)")
|
|
|
|
.arg(link()->pilotPath() )));
|
|
|
|
}
|
|
|
|
|
|
|
|
link()->fMessages->reset();
|
|
|
|
close();
|
|
|
|
|
|
|
|
// Timer already deleted by close() call.
|
|
|
|
startOpenTimer(this,fOpenTimer);
|
|
|
|
|
|
|
|
link()->fLinkStatus = WaitingForDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is an asyncronous process. We try to create a socket with the Palm
|
|
|
|
* and then bind to it (in open()). If we're able to do those 2 things, then
|
|
|
|
* we do 2 things: we set a timeout timer (which will tell us that X amount of
|
|
|
|
* time has transpired before we get into the meat of the sync transaction), and
|
|
|
|
* we also set up a TQSocketNotifier, which will tell us when data is available
|
|
|
|
* to be read from the Palm socket. If we were unable to create a socket
|
|
|
|
* and/or bind to the Palm in this method, we'll start our timer again.
|
|
|
|
*/
|
|
|
|
void DeviceCommThread::openDevice()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUPL(2);
|
|
|
|
|
|
|
|
bool deviceOpened = false;
|
|
|
|
|
|
|
|
// This transition (from Waiting to Found) can only be
|
|
|
|
// taken once.
|
|
|
|
//
|
|
|
|
if (link()->fLinkStatus == WaitingForDevice)
|
|
|
|
{
|
|
|
|
link()->fLinkStatus = FoundDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link()->fMessages->shouldPrint(Messages::OpenMessage))
|
|
|
|
{
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogMessage,
|
|
|
|
i18n("Trying to open device %1...")
|
|
|
|
.arg(link()->fPilotPath)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we're not supposed to be done, try to open the main pilot
|
|
|
|
// path...
|
|
|
|
if (!fDone && link()->fPilotPath.length() > 0)
|
|
|
|
{
|
|
|
|
DEBUGKPILOT << fname << ": Opening main pilot path: ["
|
|
|
|
<< link()->fPilotPath << "]." << endl;
|
|
|
|
deviceOpened = open(link()->fPilotPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
// only try the temp device if our earlier attempt didn't work and the temp
|
|
|
|
// device is different than the main device, and it's a non-empty
|
|
|
|
// string
|
|
|
|
bool tryTemp = !deviceOpened && (link()->fTempDevice.length() > 0) && (link()->fPilotPath != link()->fTempDevice);
|
|
|
|
|
|
|
|
// if we're not supposed to be done, and we should try the temp
|
|
|
|
// device, try the temp device...
|
|
|
|
if (!fDone && tryTemp)
|
|
|
|
{
|
|
|
|
DEBUGKPILOT << fname << ": Couldn't open main pilot path. "
|
|
|
|
<< "Now trying temp device: ["
|
|
|
|
<< link()->fTempDevice << "]." << endl;
|
|
|
|
deviceOpened = open(link()->fTempDevice);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we couldn't connect, try to connect again...
|
|
|
|
if (!fDone && !deviceOpened)
|
|
|
|
{
|
|
|
|
startOpenTimer(this, fOpenTimer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DeviceCommThread::open(const TQString &device)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUPL(2);
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
int e = 0;
|
|
|
|
TQString msg;
|
|
|
|
|
|
|
|
if (fTempSocket != -1)
|
|
|
|
{
|
|
|
|
pi_close(fTempSocket);
|
|
|
|
}
|
|
|
|
fTempSocket = (-1);
|
|
|
|
|
|
|
|
link()->fRealPilotPath
|
|
|
|
= KStandardDirs::realFilePath(device.isEmpty() ? link()->fPilotPath : device);
|
|
|
|
|
|
|
|
if ( !DeviceMap::self()->canBind(link()->fRealPilotPath) )
|
|
|
|
{
|
|
|
|
msg = i18n("Already listening on that device");
|
|
|
|
|
|
|
|
WARNINGKPILOT << "Pilot Path: ["
|
|
|
|
<< link()->fRealPilotPath << "] already connected." << endl;
|
|
|
|
WARNINGKPILOT << msg << endl;
|
|
|
|
|
|
|
|
link()->fLinkStatus = PilotLinkError;
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogError, msg));
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": Trying to create socket." << endl;
|
|
|
|
|
|
|
|
fTempSocket = pi_socket(PI_AF_PILOT, PI_SOCK_STREAM, PI_PF_DLP);
|
|
|
|
|
|
|
|
if (fTempSocket < 0)
|
|
|
|
{
|
|
|
|
e = errno;
|
|
|
|
msg = i18n("Cannot create socket for communicating "
|
|
|
|
"with the Pilot (%1)").arg(errorMessage(e));
|
|
|
|
DEBUGKPILOT << msg << endl;
|
|
|
|
DEBUGKPILOT << "(" << strerror(e) << ")" << endl;
|
|
|
|
|
|
|
|
link()->fLinkStatus = PilotLinkError;
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogError, msg));
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": Got socket: [" << fTempSocket << "]" << endl;
|
|
|
|
|
|
|
|
link()->fLinkStatus = CreatedSocket;
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": Binding to path: ["
|
|
|
|
<< link()->fRealPilotPath << "]" << endl;
|
|
|
|
|
|
|
|
ret = pi_bind(fTempSocket, TQFile::encodeName(link()->fRealPilotPath));
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": pi_bind error: ["
|
|
|
|
<< strerror(errno) << "]" << endl;
|
|
|
|
|
|
|
|
e = errno;
|
|
|
|
msg = i18n("Cannot open Pilot port \"%1\". ").arg(link()->fRealPilotPath);
|
|
|
|
|
|
|
|
DEBUGKPILOT << msg << endl;
|
|
|
|
DEBUGKPILOT << "(" << strerror(e) << ")" << endl;
|
|
|
|
|
|
|
|
link()->fLinkStatus = PilotLinkError;
|
|
|
|
|
|
|
|
if (link()->fMessages->shouldPrint(Messages::OpenFailMessage))
|
|
|
|
{
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogError, msg));
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
link()->fLinkStatus = DeviceOpen;
|
|
|
|
DeviceMap::self()->bindDevice(link()->fRealPilotPath);
|
|
|
|
|
|
|
|
fSocketNotifier = new TQSocketNotifier(fTempSocket,
|
|
|
|
TQSocketNotifier::Read, this);
|
|
|
|
TQObject::connect(fSocketNotifier, TQT_SIGNAL(activated(int)),
|
|
|
|
this, TQT_SLOT(acceptDevice()));
|
|
|
|
fSocketNotifierActive=true;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We _always_ want to set a maximum amount of time that we will wait
|
|
|
|
* for the sync process to start. In the case where our user
|
|
|
|
* has told us that he has a funky USB device, set the workaround timeout
|
|
|
|
* for shorter than normal.
|
|
|
|
*/
|
|
|
|
int timeout=20000;
|
|
|
|
if (link()->fWorkaroundUSB)
|
|
|
|
{
|
|
|
|
timeout=5000;
|
|
|
|
}
|
|
|
|
|
|
|
|
fWorkaroundUSBTimer = new TQTimer(this);
|
|
|
|
connect(fWorkaroundUSBTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(workaroundUSB()));
|
|
|
|
fWorkaroundUSBTimer->start(timeout, true);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We've been notified by our TQSocketNotifier that we have data available on the
|
|
|
|
* socket. Try to go through the remaining steps of the connnection process.
|
|
|
|
* Note: If we return at all from this before the very end without a successful
|
|
|
|
* connection, we need to make sure we restart our connection open timer, otherwise
|
|
|
|
* it won't be restarted.
|
|
|
|
*/
|
|
|
|
void DeviceCommThread::acceptDevice()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Our socket notifier should be the only reason that we end up here.
|
|
|
|
* If we're here without him being active, we have a problem. Try to clean
|
|
|
|
* up and get out.
|
|
|
|
*/
|
|
|
|
if (!fSocketNotifierActive)
|
|
|
|
{
|
|
|
|
if (!fAcceptedCount)
|
|
|
|
{
|
|
|
|
kdWarning() << k_funcinfo << ": Accidentally in acceptDevice()"
|
|
|
|
<< endl;
|
|
|
|
}
|
|
|
|
fAcceptedCount++;
|
|
|
|
if (fAcceptedCount>10)
|
|
|
|
{
|
|
|
|
// Damn the torpedoes
|
|
|
|
KPILOT_DELETE(fSocketNotifier);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fSocketNotifier)
|
|
|
|
{
|
|
|
|
// fSocketNotifier->setEnabled(false);
|
|
|
|
fSocketNotifierActive=false;
|
|
|
|
KPILOT_DELETE(fSocketNotifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": Found connection on device: ["
|
|
|
|
<< link()->pilotPath().latin1() << "]." <<endl;
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": Current status: ["
|
|
|
|
<< link()->statusString()
|
|
|
|
<< "] and socket: [" << fTempSocket << "]" << endl;
|
|
|
|
|
|
|
|
ret = pi_listen(fTempSocket, 1);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
char *s = strerror(errno);
|
|
|
|
|
|
|
|
WARNINGKPILOT << "pi_listen returned: [" << s << "]" << endl;
|
|
|
|
|
|
|
|
// Presumably, strerror() returns things in
|
|
|
|
// local8Bit and not latin1.
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogError,
|
|
|
|
i18n("Cannot listen on Pilot socket (%1)").
|
|
|
|
arg(TQString::fromLocal8Bit(s))));
|
|
|
|
reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, TQString::null, 10));
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname <<
|
|
|
|
": Listening to pilot. Now trying accept..." << endl;
|
|
|
|
|
|
|
|
int timeout = 20;
|
|
|
|
fPilotSocket = pi_accept_to(fTempSocket, 0, 0, timeout);
|
|
|
|
|
|
|
|
if (fPilotSocket < 0)
|
|
|
|
{
|
|
|
|
char *s = strerror(errno);
|
|
|
|
|
|
|
|
WARNINGKPILOT << "pi_accept returned: [" << s << "]" << endl;
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogError, i18n("Cannot accept Pilot (%1)")
|
|
|
|
.arg(TQString::fromLocal8Bit(s))));
|
|
|
|
|
|
|
|
link()->fLinkStatus = PilotLinkError;
|
|
|
|
reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": Link accept done." << endl;
|
|
|
|
|
|
|
|
if ((link()->fLinkStatus != DeviceOpen) || (fPilotSocket == -1))
|
|
|
|
{
|
|
|
|
link()->fLinkStatus = PilotLinkError;
|
|
|
|
WARNINGKPILOT << "Already connected or unable to connect!" << endl;
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogError, i18n("Cannot accept Pilot (%1)")
|
|
|
|
.arg(i18n("already connected"))));
|
|
|
|
|
|
|
|
reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, TQString::null, 30));
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": doing dlp_ReadSysInfo..." << endl;
|
|
|
|
|
|
|
|
struct SysInfo sys_info;
|
|
|
|
if (dlp_ReadSysInfo(fPilotSocket, &sys_info) < 0)
|
|
|
|
{
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogError,
|
|
|
|
i18n("Unable to read system information from Pilot")));
|
|
|
|
|
|
|
|
link()->fLinkStatus=PilotLinkError;
|
|
|
|
reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DEBUGKPILOT << fname << ": dlp_ReadSysInfo successful..." << endl;
|
|
|
|
|
|
|
|
KPILOT_DELETE(link()->fPilotSysInfo);
|
|
|
|
link()->fPilotSysInfo = new KPilotSysInfo(&sys_info);
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": RomVersion: [" << link()->fPilotSysInfo->getRomVersion()
|
|
|
|
<< "] Locale: [" << link()->fPilotSysInfo->getLocale()
|
|
|
|
<< "] Product: [" << link()->fPilotSysInfo->getProductID()
|
|
|
|
<< "]" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we've made it this far, make sure our USB workaround timer doesn't fire!
|
|
|
|
fWorkaroundUSBTimer->stop();
|
|
|
|
KPILOT_DELETE(fWorkaroundUSBTimer);
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, TQString::null, 60));
|
|
|
|
|
|
|
|
KPILOT_DELETE(link()->fPilotUser);
|
|
|
|
link()->fPilotUser = new KPilotUser;
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": doing dlp_ReadUserInfo..." << endl;
|
|
|
|
|
|
|
|
/* Ask the pilot who it is. And see if it's who we think it is. */
|
|
|
|
dlp_ReadUserInfo(fPilotSocket, link()->fPilotUser->data());
|
|
|
|
|
|
|
|
TQString n = link()->getPilotUser().name();
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": Read user name: [" << n << "]" << endl;
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, i18n("Checking last PC..."), 90));
|
|
|
|
|
|
|
|
/* Tell user (via Pilot) that we are starting things up */
|
|
|
|
if ((ret=dlp_OpenConduit(fPilotSocket)) < 0)
|
|
|
|
{
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": dlp_OpenConduit returned: [" << ret << "]" << endl;
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogError,
|
|
|
|
i18n("Could not read user information from the Pilot. "
|
|
|
|
"Perhaps you have a password set on the device?")));
|
|
|
|
|
|
|
|
}
|
|
|
|
link()->fLinkStatus = AcceptedDevice;
|
|
|
|
|
|
|
|
TQApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, TQString::null, 100));
|
|
|
|
|
|
|
|
DeviceCommEvent * ev = new DeviceCommEvent(EventDeviceReady);
|
|
|
|
ev->setCurrentSocket(fPilotSocket);
|
|
|
|
TQApplication::postEvent(link(), ev);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceCommThread::workaroundUSB()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceCommThread::run()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
fDone = false;
|
|
|
|
|
|
|
|
startOpenTimer(this, fOpenTimer);
|
|
|
|
|
|
|
|
int sleepBetweenPoll = 2;
|
|
|
|
// keep the thread alive until we're supposed to be done
|
|
|
|
while (!fDone)
|
|
|
|
{
|
|
|
|
TQThread::sleep(sleepBetweenPoll);
|
|
|
|
}
|
|
|
|
|
|
|
|
close();
|
|
|
|
// now sleep one last bit to make sure the pthread inside
|
|
|
|
// pilot-link (potentially, if it's libusb) is done before we exit
|
|
|
|
TQThread::sleep(1);
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": comm thread now done..." << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
KPilotDeviceLink::KPilotDeviceLink(TQObject * parent, const char *name,
|
|
|
|
const TQString &tempDevice) :
|
|
|
|
KPilotLink(parent, name), fLinkStatus(Init), fWorkaroundUSB(false),
|
|
|
|
fPilotSocket(-1), fTempDevice(tempDevice), fMessages(new Messages(this)), fDeviceCommThread(0L)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": Pilot-link version: [" << PILOT_LINK_NUMBER
|
|
|
|
<< "]" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
KPilotDeviceLink::~KPilotDeviceLink()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
close();
|
|
|
|
KPILOT_DELETE(fPilotSysInfo);
|
|
|
|
KPILOT_DELETE(fPilotUser);
|
|
|
|
KPILOT_DELETE(fMessages);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */bool KPilotDeviceLink::isConnected() const
|
|
|
|
{
|
|
|
|
return fLinkStatus == AcceptedDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */bool KPilotDeviceLink::event(TQEvent *e)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
bool handled = false;
|
|
|
|
|
|
|
|
if ((int)e->type() == EventDeviceReady)
|
|
|
|
{
|
|
|
|
DeviceCommEvent* t = static_cast<DeviceCommEvent*>(e);
|
|
|
|
fPilotSocket = t->currentSocket();
|
|
|
|
emit deviceReady( this);
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
else if ((int)e->type() == EventLogMessage)
|
|
|
|
{
|
|
|
|
DeviceCommEvent* t = static_cast<DeviceCommEvent*>(e);
|
|
|
|
emit logMessage(t->message());
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
else if ((int)e->type() == EventLogError)
|
|
|
|
{
|
|
|
|
DeviceCommEvent* t = static_cast<DeviceCommEvent*>(e);
|
|
|
|
emit logError(t->message());
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
else if ((int)e->type() == EventLogProgress)
|
|
|
|
{
|
|
|
|
DeviceCommEvent* t = static_cast<DeviceCommEvent*>(e);
|
|
|
|
emit logProgress(t->message(), t->progress());
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
handled = KPilotLink::event(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KPilotDeviceLink::stopCommThread()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
if (fDeviceCommThread)
|
|
|
|
{
|
|
|
|
fDeviceCommThread->setDone(true);
|
|
|
|
|
|
|
|
// try to wait for our thread to finish, but don't
|
|
|
|
// block the main thread forever
|
|
|
|
if (fDeviceCommThread->running())
|
|
|
|
{
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": comm thread still running. "
|
|
|
|
<< "waiting for it to complete." << endl;
|
|
|
|
bool done = fDeviceCommThread->wait(5000);
|
|
|
|
if (!done)
|
|
|
|
{
|
|
|
|
DEBUGKPILOT << fname
|
|
|
|
<< ": comm thread still running "
|
|
|
|
<< "after wait(). "
|
|
|
|
<< "going to have to terminate it."
|
|
|
|
<< endl;
|
|
|
|
// not normally to be done, but we must make sure
|
|
|
|
// that this device doesn't come back alive
|
|
|
|
fDeviceCommThread->terminate();
|
|
|
|
fDeviceCommThread->wait();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fDeviceCommThread->close();
|
|
|
|
|
|
|
|
KPILOT_DELETE(fDeviceCommThread);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KPilotDeviceLink::close()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
stopCommThread();
|
|
|
|
|
|
|
|
fPilotSocket = (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KPilotDeviceLink::reset(const TQString & dP)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
fLinkStatus = Init;
|
|
|
|
|
|
|
|
// Release all resources
|
|
|
|
//
|
|
|
|
close();
|
|
|
|
fPilotPath = TQString::null;
|
|
|
|
|
|
|
|
fPilotPath = dP;
|
|
|
|
if (fPilotPath.isEmpty())
|
|
|
|
fPilotPath = fTempDevice;
|
|
|
|
if (fPilotPath.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KPilotDeviceLink::startCommThread()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
stopCommThread();
|
|
|
|
|
|
|
|
if (fTempDevice.isEmpty() && pilotPath().isEmpty())
|
|
|
|
{
|
|
|
|
WARNINGKPILOT << "No point in trying empty device."
|
|
|
|
<< endl;
|
|
|
|
|
|
|
|
TQString msg = i18n("The Pilot device is not configured yet.");
|
|
|
|
WARNINGKPILOT << msg << endl;
|
|
|
|
|
|
|
|
fLinkStatus = PilotLinkError;
|
|
|
|
|
|
|
|
emit logError(msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fDeviceCommThread = new DeviceCommThread(this);
|
|
|
|
fDeviceCommThread->start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KPilotDeviceLink::reset()
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
fMessages->reset();
|
|
|
|
close();
|
|
|
|
|
|
|
|
checkDevice();
|
|
|
|
|
|
|
|
fLinkStatus = WaitingForDevice;
|
|
|
|
|
|
|
|
startCommThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KPilotDeviceLink::checkDevice()
|
|
|
|
{
|
|
|
|
// If the device exists yet doesn't have the right
|
|
|
|
// permissions, complain and then continue anyway.
|
|
|
|
//
|
|
|
|
TQFileInfo fi(fPilotPath);
|
|
|
|
if (fi.exists())
|
|
|
|
{
|
|
|
|
// If it exists, it ought to be RW already.
|
|
|
|
//
|
|
|
|
if (!(fi.isReadable() && fi.isWritable()))
|
|
|
|
{
|
|
|
|
emit logError(i18n("Pilot device %1 is not read-write.")
|
|
|
|
.arg(fPilotPath));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// It doesn't exist, mention this in the log
|
|
|
|
// (relevant as long as we use only one device type)
|
|
|
|
//
|
|
|
|
emit
|
|
|
|
logError(i18n("Pilot device %1 does not exist. "
|
|
|
|
"Probably it is a USB device and will appear during a HotSync.")
|
|
|
|
.arg(fPilotPath));
|
|
|
|
// Suppress all normal and error messages about opening the device.
|
|
|
|
fMessages->block(Messages::OpenMessage | Messages::OpenFailMessage,
|
|
|
|
true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KPilotDeviceLink::setTempDevice(const TQString &d)
|
|
|
|
{
|
|
|
|
fTempDevice = d;
|
|
|
|
DeviceMap::self()->bindDevice(fTempDevice);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */bool KPilotDeviceLink::tickle()
|
|
|
|
{
|
|
|
|
// No FUNCTIONSETUP here because it may be called from
|
|
|
|
// a separate thread.
|
|
|
|
return pi_tickle(pilotSocket()) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virtual */void KPilotDeviceLink::addSyncLogEntryImpl(const TQString &entry)
|
|
|
|
{
|
|
|
|
dlp_AddSyncLogEntry(fPilotSocket,
|
|
|
|
const_cast<char *>((const char *)Pilot::toPilot(entry)));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KPilotDeviceLink::installFile(const TQString & f, const bool deleteFile)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": Installing file " << f << endl;
|
|
|
|
|
|
|
|
if (!TQFile::exists(f))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
char buffer[PATH_MAX];
|
|
|
|
memset(buffer, 0, PATH_MAX);
|
|
|
|
strlcpy(buffer, TQFile::encodeName(f), PATH_MAX);
|
|
|
|
struct pi_file *pf = pi_file_open(buffer);
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
WARNINGKPILOT << "Cannot open file " << f << endl;
|
|
|
|
emit logError(i18n
|
|
|
|
("<qt>Cannot install the file "%1".</qt>").
|
|
|
|
arg(f));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pi_file_install(pf, fPilotSocket, 0, 0L) < 0)
|
|
|
|
{
|
|
|
|
WARNINGKPILOT << "Cannot pi_file_install " << f << endl;
|
|
|
|
emit logError(i18n
|
|
|
|
("<qt>Cannot install the file "%1".</qt>").
|
|
|
|
arg(f));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
pi_file_close(pf);
|
|
|
|
if (deleteFile)
|
|
|
|
TQFile::remove(f);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int KPilotDeviceLink::openConduit()
|
|
|
|
{
|
|
|
|
return dlp_OpenConduit(fPilotSocket);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KPilotDeviceLink::statusString(LinkStatus l)
|
|
|
|
{
|
|
|
|
TQString s= CSL1("KPilotDeviceLink=");
|
|
|
|
|
|
|
|
switch (l)
|
|
|
|
{
|
|
|
|
case Init:
|
|
|
|
s.append(CSL1("Init"));
|
|
|
|
break;
|
|
|
|
case WaitingForDevice:
|
|
|
|
s.append(CSL1("WaitingForDevice"));
|
|
|
|
break;
|
|
|
|
case FoundDevice:
|
|
|
|
s.append(CSL1("FoundDevice"));
|
|
|
|
break;
|
|
|
|
case CreatedSocket:
|
|
|
|
s.append(CSL1("CreatedSocket"));
|
|
|
|
break;
|
|
|
|
case DeviceOpen:
|
|
|
|
s.append(CSL1("DeviceOpen"));
|
|
|
|
break;
|
|
|
|
case AcceptedDevice:
|
|
|
|
s.append(CSL1("AcceptedDevice"));
|
|
|
|
break;
|
|
|
|
case SyncDone:
|
|
|
|
s.append(CSL1("SyncDone"));
|
|
|
|
break;
|
|
|
|
case PilotLinkError:
|
|
|
|
s.append(CSL1("PilotLinkError"));
|
|
|
|
break;
|
|
|
|
case WorkaroundUSB:
|
|
|
|
s.append(CSL1("WorkaroundUSB"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KPilotDeviceLink::statusString() const
|
|
|
|
{
|
|
|
|
return statusString(status() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KPilotDeviceLink::endSync(EndOfSyncFlags f)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
if (UpdateUserInfo == f)
|
|
|
|
{
|
|
|
|
getPilotUser().setLastSyncPC((unsigned long) gethostid());
|
|
|
|
getPilotUser().setLastSyncDate(time(0));
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": Writing username " << getPilotUser().name() << endl;
|
|
|
|
|
|
|
|
dlp_WriteUserInfo(pilotSocket(), getPilotUser().data());
|
|
|
|
addSyncLogEntry(i18n("End of HotSync\n"));
|
|
|
|
}
|
|
|
|
dlp_EndOfSync(pilotSocket(), 0);
|
|
|
|
KPILOT_DELETE(fPilotSysInfo);
|
|
|
|
KPILOT_DELETE(fPilotUser);
|
|
|
|
}
|
|
|
|
|
|
|
|
int KPilotDeviceLink::getNextDatabase(int index, struct DBInfo *dbinfo)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
pi_buffer_t buf = { 0, 0, 0 };
|
|
|
|
int r = dlp_ReadDBList(pilotSocket(), 0, dlpDBListRAM, index, &buf);
|
|
|
|
if (r >= 0)
|
|
|
|
{
|
|
|
|
memcpy(dbinfo, buf.data, sizeof(struct DBInfo));
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a database with the given name. Info about the DB is stored into dbinfo (e.g. to be used later on with retrieveDatabase).
|
|
|
|
int KPilotDeviceLink::findDatabase(const char *name, struct DBInfo *dbinfo,
|
|
|
|
int index, unsigned long type, unsigned long creator)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
return dlp_FindDBInfo(pilotSocket(), 0, index, const_cast<char *>(name),
|
|
|
|
type, creator, dbinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KPilotDeviceLink::retrieveDatabase(const TQString &fullBackupName,
|
|
|
|
DBInfo *info)
|
|
|
|
{
|
|
|
|
FUNCTIONSETUP;
|
|
|
|
|
|
|
|
if (fullBackupName.isEmpty() || !info)
|
|
|
|
{
|
|
|
|
// Don't even bother trying to convert or retrieve.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUGKPILOT << fname << ": Writing DB <" << info->name << "> "
|
|
|
|
<< " to " << fullBackupName << endl;
|
|
|
|
|
|
|
|
TQCString encodedName = TQFile::encodeName(fullBackupName);
|
|
|
|
struct pi_file *f = pi_file_create(encodedName, info);
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
WARNINGKPILOT << "Failed, unable to create file" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pi_file_retrieve(f, pilotSocket(), 0, 0L) < 0)
|
|
|
|
{
|
|
|
|
WARNINGKPILOT << "Failed, unable to back up database" << endl;
|
|
|
|
|
|
|
|
pi_file_close(f);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
pi_file_close(f);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
KPilotLink::DBInfoList KPilotDeviceLink::getDBList(int cardno, int flags)
|
|
|
|
{
|
|
|
|
bool cont=true;
|
|
|
|
DBInfoList dbs;
|
|
|
|
int index=0;
|
|
|
|
while (cont)
|
|
|
|
{
|
|
|
|
pi_buffer_t buf = { 0, 0, 0 };
|
|
|
|
pi_buffer_clear(&buf);
|
|
|
|
// DBInfo*dbi=new DBInfo();
|
|
|
|
if (dlp_ReadDBList(pilotSocket(), cardno, flags | dlpDBListMultiple,
|
|
|
|
index, &buf)<0)
|
|
|
|
{
|
|
|
|
cont=false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBInfo db_n;
|
|
|
|
DBInfo *db_it = (DBInfo *)buf.data;
|
|
|
|
int info_count = buf.used / sizeof(struct DBInfo);
|
|
|
|
|
|
|
|
while (info_count>0)
|
|
|
|
{
|
|
|
|
memcpy(&db_n, db_it, sizeof(struct DBInfo));
|
|
|
|
++db_it;
|
|
|
|
info_count--;
|
|
|
|
dbs.append(db_n);
|
|
|
|
}
|
|
|
|
index=db_n.index+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dbs;
|
|
|
|
}
|
|
|
|
|
|
|
|
const KPilotCard *KPilotDeviceLink::getCardInfo(int card)
|
|
|
|
{
|
|
|
|
KPilotCard *cardinfo=new KPilotCard();
|
|
|
|
if (dlp_ReadStorageInfo(pilotSocket(), card, cardinfo->cardInfo())<0)
|
|
|
|
{
|
|
|
|
WARNINGKPILOT << "Could not get info for card " << card << endl;
|
|
|
|
|
|
|
|
KPILOT_DELETE(cardinfo);
|
|
|
|
return 0L;
|
|
|
|
}
|
|
|
|
return cardinfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
PilotDatabase *KPilotDeviceLink::database(const TQString &name)
|
|
|
|
{
|
|
|
|
return new PilotSerialDatabase( this, name );
|
|
|
|
}
|
|
|
|
|
|
|
|
PilotDatabase *KPilotDeviceLink::database(const DBInfo *info)
|
|
|
|
{
|
|
|
|
return new PilotSerialDatabase( this, info );
|
|
|
|
}
|
|
|
|
|