diff options
Diffstat (limited to 'kpilot/lib/kpilotdevicelink.cc')
-rw-r--r-- | kpilot/lib/kpilotdevicelink.cc | 966 |
1 files changed, 966 insertions, 0 deletions
diff --git a/kpilot/lib/kpilotdevicelink.cc b/kpilot/lib/kpilotdevicelink.cc new file mode 100644 index 000000000..55027d763 --- /dev/null +++ b/kpilot/lib/kpilotdevicelink.cc @@ -0,0 +1,966 @@ +/* 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 <qdir.h> +#include <qtimer.h> +#include <qdatetime.h> +#include <qthread.h> +#include <qsocketnotifier.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, QTimer *&t) +{ + if ( !t) + { + t = new QTimer(dev); + QObject::connect(t, SIGNAL(timeout()), dev, SLOT(openDevice())); + } + // just a single-shot timer. we'll know when to start it again... + t->start(1000, true); +} + +DeviceCommThread::DeviceCommThread(KPilotDeviceLink *d) : + QThread(), + 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)) + { + QApplication::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 QSocketNotifier, 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)) + { + QApplication::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 QString &device) +{ + FUNCTIONSETUPL(2); + + int ret; + int e = 0; + QString 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; + + QApplication::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; + + QApplication::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, QFile::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)) + { + QApplication::postEvent(link(), new DeviceCommEvent(EventLogError, msg)); + } + + return false; + } + + link()->fLinkStatus = DeviceOpen; + DeviceMap::self()->bindDevice(link()->fRealPilotPath); + + fSocketNotifier = new QSocketNotifier(fTempSocket, + QSocketNotifier::Read, this); + QObject::connect(fSocketNotifier, SIGNAL(activated(int)), + this, 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 QTimer(this); + connect(fWorkaroundUSBTimer, SIGNAL(timeout()), this, SLOT(workaroundUSB())); + fWorkaroundUSBTimer->start(timeout, true); + + return true; +} + +/** + * We've been notified by our QSocketNotifier 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. + QApplication::postEvent(link(), new DeviceCommEvent(EventLogError, + i18n("Cannot listen on Pilot socket (%1)"). + arg(QString::fromLocal8Bit(s)))); + reset(); + return; + } + + QApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, QString::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; + + QApplication::postEvent(link(), new DeviceCommEvent(EventLogError, i18n("Cannot accept Pilot (%1)") + .arg(QString::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; + + QApplication::postEvent(link(), new DeviceCommEvent(EventLogError, i18n("Cannot accept Pilot (%1)") + .arg(i18n("already connected")))); + + reset(); + return; + } + + QApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, QString::null, 30)); + + DEBUGKPILOT << fname << ": doing dlp_ReadSysInfo..." << endl; + + struct SysInfo sys_info; + if (dlp_ReadSysInfo(fPilotSocket, &sys_info) < 0) + { + QApplication::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); + + QApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, QString::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()); + + QString n = link()->getPilotUser().name(); + DEBUGKPILOT << fname + << ": Read user name: [" << n << "]" << endl; + + QApplication::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; + + QApplication::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; + + QApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, QString::null, 100)); + + DeviceCommEvent * ev = new DeviceCommEvent(EventDeviceReady); + ev->setCurrentSocket(fPilotSocket); + QApplication::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) + { + QThread::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 + QThread::sleep(1); + + DEBUGKPILOT << fname << ": comm thread now done..." << endl; +} + +KPilotDeviceLink::KPilotDeviceLink(QObject * parent, const char *name, + const QString &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(QEvent *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 QString & dP) +{ + FUNCTIONSETUP; + + fLinkStatus = Init; + + // Release all resources + // + close(); + fPilotPath = QString::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; + + QString 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. + // + QFileInfo 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 QString &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 QString &entry) +{ + dlp_AddSyncLogEntry(fPilotSocket, + const_cast<char *>((const char *)Pilot::toPilot(entry))); +} + +bool KPilotDeviceLink::installFile(const QString & f, const bool deleteFile) +{ + FUNCTIONSETUP; + + DEBUGKPILOT << fname << ": Installing file " << f << endl; + + if (!QFile::exists(f)) + return false; + + char buffer[PATH_MAX]; + memset(buffer, 0, PATH_MAX); + strlcpy(buffer, QFile::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) + QFile::remove(f); + + return true; +} + +int KPilotDeviceLink::openConduit() +{ + return dlp_OpenConduit(fPilotSocket); +} + +QString KPilotDeviceLink::statusString(LinkStatus l) +{ + QString 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; +} + +QString 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 QString &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; + + QCString encodedName = QFile::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 QString &name) +{ + return new PilotSerialDatabase( this, name ); +} + +PilotDatabase *KPilotDeviceLink::database(const DBInfo *info) +{ + return new PilotSerialDatabase( this, info ); +} + |