|
|
|
#ifndef _KPILOT_KPILOTLINK_H
|
|
|
|
#define _KPILOT_KPILOTLINK_H
|
|
|
|
/* KPilot
|
|
|
|
**
|
|
|
|
** Copyright (C) 1998-2001 by Dan Pilone
|
|
|
|
** Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
|
|
|
|
** Copyright (C) 2006 Adriaan de Groot <groot@kde.org>
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
** 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 <pi-dlp.h>
|
|
|
|
|
|
|
|
#include <tqobject.h>
|
|
|
|
#include <tqvaluelist.h>
|
|
|
|
|
|
|
|
/** @file
|
|
|
|
* Encapsulates all the communication with the handheld. Also
|
|
|
|
* does daemon-like polling of the handheld. Interesting status
|
|
|
|
* changes are signalled.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class TQThread;
|
|
|
|
class KPilotUser;
|
|
|
|
class KPilotSysInfo;
|
|
|
|
class KPilotCard;
|
|
|
|
class PilotDatabase;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* KPilotLink handles some aspects of
|
|
|
|
* communication with a Handheld. A KPilotLink object represents a
|
|
|
|
* connection to a device (which may be active or inactive -- the latter in
|
|
|
|
* cases where the link is @e waiting for a device to show up). The object
|
|
|
|
* handles waiting, protocol initialization and some general
|
|
|
|
* tasks such as getting system information or user data.
|
|
|
|
*
|
|
|
|
* The actual communication with the handheld should use the
|
|
|
|
* PilotDatabase methods or use pilot-link dlp_* functions directly
|
|
|
|
* on the file descriptor returned by handle().
|
|
|
|
*
|
|
|
|
* Implementations of this abstract class are KPilotDeviceLink
|
|
|
|
* (for real physical devices) and KPilotLocalLink (for devices
|
|
|
|
* represented by an on-disk directory).
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @section General
|
|
|
|
*
|
|
|
|
* A KPilotLink object (or one of its subclasses) represents a single
|
|
|
|
* (potential) link to a handheld device. The handheld device may be
|
|
|
|
* a real physical one (subclass KPilotDeviceLink) or a virtual one
|
|
|
|
* (subclass KPilotLocalLink). Every KPilotLink is associated with exactly
|
|
|
|
* one identifier for @em what device it is attached to. Physical devices
|
|
|
|
* have physical locations as interpreted by libpisock -- /dev/ttyUSB0 for
|
|
|
|
* instance, or net:any -- while virtual devices are associated with a location
|
|
|
|
* in the filesystem.
|
|
|
|
*
|
|
|
|
* A particular KPilotLink object may be connected -- communicating with
|
|
|
|
* a device -- or not. For physical devices, that means that the device is
|
|
|
|
* attached to the system (for USB-connected devices, think of it as a
|
|
|
|
* metaphor in the case of net:any) and that the HotSync button has been
|
|
|
|
* pressed. Virtual devices are immediately connected on creation, since there
|
|
|
|
* is no sensible "not connected" state. A connected KPilotLink has access to the
|
|
|
|
* data on the handheld and can give that data to the rest of the application.
|
|
|
|
*
|
|
|
|
* The data access API is divided into roughly three parts, with tickle handling
|
|
|
|
* being a special fourth part (see section below). These are:
|
|
|
|
*
|
|
|
|
* - Message logging
|
|
|
|
* - System information access
|
|
|
|
* - Database access
|
|
|
|
*
|
|
|
|
* @section Lifecycle
|
|
|
|
*
|
|
|
|
* The life-cycle of a KPilotLink object is as follows:
|
|
|
|
*
|
|
|
|
* # Object is created (one of the concrete subclasses, anyway)
|
|
|
|
* # Object gets a location assigned through reset(const TQString &)
|
|
|
|
* # Object is connected to the handheld device (somehow, depends on subclass)
|
|
|
|
* # Object emits signal deviceReady()
|
|
|
|
*
|
|
|
|
* After this, the application is free to use the API to access the information from
|
|
|
|
* the handheld. When the device connection is no longer needed, call either
|
|
|
|
* endOfSync() or finishSync() to wrap up the communications. The object remains
|
|
|
|
* alive and may be re-used by calling reset() to use the same location or
|
|
|
|
* reset(const TQString &) to give it a new location.
|
|
|
|
*
|
|
|
|
* @section Tickle handling.
|
|
|
|
*
|
|
|
|
* During a HotSync, the Pilot expects to be kept awake by (nearly)
|
|
|
|
* continuous communication with the PC. The Pilot doesn't like
|
|
|
|
* long periods of inactivity, since they drain the batteries while
|
|
|
|
* the communications hardware is kept powered up. If the period of
|
|
|
|
* inactivity is too long, the Pilot times out, shuts down the
|
|
|
|
* communication, and the HotSync is broken.
|
|
|
|
|
|
|
|
* Sometimes, however, periods of inactivity cannot be avoided --
|
|
|
|
* for instance, if you _have_ to ask the user something during a
|
|
|
|
* sync, or if you are fetching a large amount of data from a slow
|
|
|
|
* source (libtdeabc can do that, if your addressbook is on an LDAP
|
|
|
|
* server). During these periods of inactivity (as far as the Pilot
|
|
|
|
* can tell), you can "tickle" the Pilot to keep it awake. This
|
|
|
|
* prevents the communications from being shut down. It's not
|
|
|
|
* a good idea to do this all the time -- battery life and possible
|
|
|
|
* corruption of the dlp_ communications streams. Hence, you should
|
|
|
|
* start and stop tickling the Pilot around any computation which:
|
|
|
|
* - may take a long time
|
|
|
|
* - does not in itself @em ever communicate directly with the Pilot
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* You can call slot tickle() whenever you like just to do a
|
|
|
|
* dlp_tickle() call on the Pilot. It will return true if the
|
|
|
|
* tickle was successful, false otherwise (this can be used to
|
|
|
|
* detect if the communication with the Pilot has shut down for
|
|
|
|
* some reason).
|
|
|
|
*
|
|
|
|
* The protected methods startTickle() and stopTickle() are intended
|
|
|
|
* to be called only from SyncActions -- I can't think of any other
|
|
|
|
* legitimate use, since everything being done during a HotSync is
|
|
|
|
* done via subclasses of SyncActions anyway, and SyncAction provides
|
|
|
|
* access to these methods though its own start- and stopTickle().
|
|
|
|
*
|
|
|
|
* Call startTickle with a timeout in seconds, or 0 for no timeout.
|
|
|
|
* This timeout is _unrelated_ to the timeout in the Pilot's
|
|
|
|
* communications. Instead, it indicates how long to continue
|
|
|
|
* tickling the Pilot before emitting the timeout() signal. This
|
|
|
|
* can be useful for placing an upper bound on the amount of
|
|
|
|
* time to wait for, say, user interaction -- you don't want an
|
|
|
|
* inattentive user to drain the batteries during a sync because
|
|
|
|
* he doesn't click on "Yes" for some question. If you pass a
|
|
|
|
* timeout of 0, the Pilot will continue to be tickled until you
|
|
|
|
* call stopTickle().
|
|
|
|
*
|
|
|
|
* Call stopTickle() to stop tickling the Pilot and continue with
|
|
|
|
* normal operation. You @em must call stopTickle() before calling
|
|
|
|
* anything else that might communicate with the Pilot, to avoid
|
|
|
|
* corrupting the dlp_ communications stream. (TODO: Mutex the heck
|
|
|
|
* out of this to avoid this problem). Note that stopTickle() may
|
|
|
|
* hang up the caller for a small amount of time (up to 200ms)
|
|
|
|
* before returning.
|
|
|
|
*
|
|
|
|
* event() and TickleTimeoutEvent are part of the implementation
|
|
|
|
* of tickling, and are only accidentally visible.
|
|
|
|
*
|
|
|
|
* Signal timeout() is emitted if startTickle() has been called
|
|
|
|
* with a non-zero timeout and that timeout has elapsed. The
|
|
|
|
* tickler is stopped before timeout is emitted.
|
|
|
|
*/
|
|
|
|
class KDE_EXPORT KPilotLink : public TQObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
friend class SyncAction;
|
|
|
|
public:
|
|
|
|
/** A list of DBInfo structures. */
|
|
|
|
typedef TQValueList<struct DBInfo> DBInfoList;
|
|
|
|
|
|
|
|
/** Constructor. Use reset() to start looking for a device. */
|
|
|
|
KPilotLink( TQObject *parent = 0, const char *name = 0 );
|
|
|
|
|
|
|
|
/** Destructor. This rudely interrupts any communication in progress.
|
|
|
|
* It is best to call endOfSync() or finishSync() before destroying
|
|
|
|
* the device.
|
|
|
|
*/
|
|
|
|
virtual ~KPilotLink();
|
|
|
|
|
|
|
|
|
|
|
|
/** Provides a human-readable status string. */
|
|
|
|
virtual TQString statusString() const = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* True if HotSync has been started but not finished yet
|
|
|
|
* (ie. the physical Pilot is waiting for sync commands)
|
|
|
|
*/
|
|
|
|
virtual bool isConnected() const = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Information on what kind of device we're dealing with.
|
|
|
|
* A link is associated with a path -- either the node in
|
|
|
|
* /dev that the physical device is attached to, or an
|
|
|
|
* IP address, or a filesystem path for local links.
|
|
|
|
* Whichever is being used, this function returns its
|
|
|
|
* name in a human-readable form.
|
|
|
|
*/
|
|
|
|
TQString pilotPath() const
|
|
|
|
{
|
|
|
|
return fPilotPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the device link to the Init state and try connecting
|
|
|
|
* to the given device path (if it's non-empty). What the
|
|
|
|
* path means depends on the kind of link we're instantiating.
|
|
|
|
*
|
|
|
|
* @see reset()
|
|
|
|
* @see pilotPath()
|
|
|
|
*/
|
|
|
|
virtual void reset(const TQString &pilotPath) = 0;
|
|
|
|
|
|
|
|
/** Allows our class to receive custom events that our threads
|
|
|
|
* will be giving to us, including tickle timeouts and
|
|
|
|
* device communication events.
|
|
|
|
*/
|
|
|
|
virtual bool event(TQEvent *e);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Install the list of files (full paths!) named by @p l
|
|
|
|
* onto the handheld (or whatever this link represents).
|
|
|
|
* If @p deleteFiles is true, the source files are removed.
|
|
|
|
*
|
|
|
|
* @return the number of files successfully installed.
|
|
|
|
*/
|
|
|
|
unsigned int installFiles(const TQStringList &l, const bool deleteFiles);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write a log entry to the handheld. If @p log is true,
|
|
|
|
* then the signal logMessage() is also emitted. This
|
|
|
|
* function is supposed to @em only write to the handheld's
|
|
|
|
* log (with a physical device, that is what appears on
|
|
|
|
* screen at the end of a sync).
|
|
|
|
*/
|
|
|
|
void addSyncLogEntry(const TQString &entry,bool log=true);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find a database with the given @p name (and optionally,
|
|
|
|
* type @p type and creator ID (from pi_mktag) @p creator,
|
|
|
|
* on searching from index @p index on the handheld.
|
|
|
|
* Fills in the DBInfo structure @p info if found.
|
|
|
|
*
|
|
|
|
* @return >=0 on success. See the documentation for each
|
|
|
|
* subclass for particular meanings.
|
|
|
|
* @return < 0 on error.
|
|
|
|
*/
|
|
|
|
virtual int findDatabase(const char *name,
|
|
|
|
struct DBInfo *info,
|
|
|
|
int index=0,
|
|
|
|
unsigned long type=0,
|
|
|
|
unsigned long creator=0) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the database indicated by DBInfo @p *db into the
|
|
|
|
* local file @p path. This copies all the data, and you can
|
|
|
|
* create a PilotLocalDatabase from the resulting @p path .
|
|
|
|
*
|
|
|
|
* @return @c true on success
|
|
|
|
*/
|
|
|
|
virtual bool retrieveDatabase(const TQString &path, struct DBInfo *db) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fill the DBInfo structure @p db with information about
|
|
|
|
* the next database (in some ordering) counting from
|
|
|
|
* @p index.
|
|
|
|
*
|
|
|
|
* @return < 0 on error
|
|
|
|
*/
|
|
|
|
virtual int getNextDatabase(int index,struct DBInfo *db) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a list of DBInfo structures describing all the
|
|
|
|
* databases available on the link (ie. device) with the
|
|
|
|
* given card number @p cardno and flags @p flags. No known
|
|
|
|
* handheld uses a cardno other than 0; use flags to
|
|
|
|
* indicate what kind of databases to fetch -- @c dlpDBListRAM
|
|
|
|
* or @c dlpDBListROM.
|
|
|
|
*
|
|
|
|
* @return list of DBInfo objects, one for each database
|
|
|
|
* @note ownership of the DBInfo objects is passed to the
|
|
|
|
* caller, who must delete the objects.
|
|
|
|
*/
|
|
|
|
virtual DBInfoList getDBList(int cardno=0, int flags=dlpDBListRAM) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a database object for manipulating the database with
|
|
|
|
* name @p name on the link. This database may be local or
|
|
|
|
* remote, depending on the kind of link in use.
|
|
|
|
*
|
|
|
|
* @return pointer to database object, or 0 on error.
|
|
|
|
* @note ownership of the database object is given to the caller,
|
|
|
|
* who must delete the object in time.
|
|
|
|
*/
|
|
|
|
virtual PilotDatabase *database( const TQString &name ) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a database object for manipulating the database with
|
|
|
|
* the name stored in the DBInfo structure @p info . The default
|
|
|
|
* version goes through method database( const TQString & ), above.
|
|
|
|
*
|
|
|
|
* @return pointer to database object, or 0 on error.
|
|
|
|
* @note ownership of the database object is given to the caller.
|
|
|
|
*/
|
|
|
|
virtual PilotDatabase *database( const DBInfo *info );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the user information from the device. Ownership
|
|
|
|
* is kept by the link, and at the end of a sync the user
|
|
|
|
* information is synced back to the link -- so it may be
|
|
|
|
* modified, but don't make local copies of it.
|
|
|
|
*
|
|
|
|
* @note Do not call this before the sync begins!
|
|
|
|
*/
|
|
|
|
KPilotUser &getPilotUser()
|
|
|
|
{
|
|
|
|
return *fPilotUser;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* System information about the handheld. Ownership is kept
|
|
|
|
* by the link. For non-device links, something fake is
|
|
|
|
* returned.
|
|
|
|
*
|
|
|
|
* @note Do not call this before the sync begins!
|
|
|
|
*/
|
|
|
|
const KPilotSysInfo &getSysInfo()
|
|
|
|
{
|
|
|
|
return *fPilotSysInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve information about the data card @p card;
|
|
|
|
* I don't think that any pilot supports card numbers
|
|
|
|
* other than 0. Non-device links return something fake.
|
|
|
|
*
|
|
|
|
* This function may return NULL (non-device links or
|
|
|
|
* on error).
|
|
|
|
*
|
|
|
|
* @note Ownership of the KPilotCard object is given
|
|
|
|
* to the caller, who must delete it.
|
|
|
|
*/
|
|
|
|
virtual const KPilotCard *getCardInfo(int card=0) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* When ending the sync, you can do so gracefully, updating the
|
|
|
|
* last-sync time to indicate a successful sync and setting the
|
|
|
|
* user name on the device, or you can skip that (for unsuccessful
|
|
|
|
* syncs, generally).
|
|
|
|
*/
|
|
|
|
enum EndOfSyncFlags {
|
|
|
|
NoUpdate, ///< Do not update the user info
|
|
|
|
UpdateUserInfo ///< Update user info and last successful sync date
|
|
|
|
} ;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Custom events we can be handling...
|
|
|
|
*/
|
|
|
|
enum CustomEvents {
|
|
|
|
EventTickleTimeout = 1066
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* End the sync in a gracuful manner. If @p f is UpdateUserInfo,
|
|
|
|
* the sync was successful and the user info and last successful sync
|
|
|
|
* timestamp are updated.
|
|
|
|
*/
|
|
|
|
virtual void endSync( EndOfSyncFlags f ) = 0;
|
|
|
|
|
|
|
|
signals:
|
|
|
|
/**
|
|
|
|
* A timeout associated with tickling has occurred. Each
|
|
|
|
* time startTickle() is called, you can state how long
|
|
|
|
* tickling should last (at most) before timing out.
|
|
|
|
*
|
|
|
|
* You can only get a timeout when the TQt event loop is
|
|
|
|
* running, which somewhat limits the usefulness of timeouts.
|
|
|
|
*/
|
|
|
|
void timeout();
|
|
|
|
|
|
|
|
/** Signal that a message has been written to the sync log. */
|
|
|
|
void logMessage(const TQString &);
|
|
|
|
|
|
|
|
/** Signal that an error has occurred, for logging. */
|
|
|
|
void logError(const TQString &);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Signal that progress has been made, for logging purposes.
|
|
|
|
* @p p is the percentage completed (0 <= s <= 100).
|
|
|
|
* The string @p s is logged as well, if non-Null.
|
|
|
|
*/
|
|
|
|
void logProgress(const TQString &s, int p);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Emitted once the user information has been read and
|
|
|
|
* the HotSync is really ready to go.
|
|
|
|
*/
|
|
|
|
void deviceReady( KPilotLink * );
|
|
|
|
|
|
|
|
|
|
|
|
public slots:
|
|
|
|
/**
|
|
|
|
* Release all resources, including the master pilot socket,
|
|
|
|
* timers, etc.
|
|
|
|
*/
|
|
|
|
virtual void close() = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Assuming things have been set up at least once already by
|
|
|
|
* a call to reset() with parameters, use this slot to re-start
|
|
|
|
* with the same settings.
|
|
|
|
*/
|
|
|
|
virtual void reset() = 0;
|
|
|
|
|
|
|
|
/** Tickle the underlying device exactly once. */
|
|
|
|
virtual bool tickle() = 0;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
/**
|
|
|
|
* Path of the device special file that will be used.
|
|
|
|
* Usually /dev/pilot, /dev/ttySx, or /dev/usb/x. May be
|
|
|
|
* a filesystem path for local links.
|
|
|
|
*/
|
|
|
|
TQString fPilotPath;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start tickling the Handheld (every few seconds). This
|
|
|
|
* lasts until @p timeout seconds have passed (or forever
|
|
|
|
* if @p timeout is zero).
|
|
|
|
*
|
|
|
|
* @note Do not call startTickle() twice with no intervening
|
|
|
|
* stopTickle().
|
|
|
|
*/
|
|
|
|
void startTickle(unsigned int timeout=0);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop tickling the Handheld. This may block for some
|
|
|
|
* time (less than a second) to allow the tickle thread
|
|
|
|
* to finish.
|
|
|
|
*/
|
|
|
|
void stopTickle();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Install a single file onto the device link. Full pathname
|
|
|
|
* @p f is used; in addition, if @p deleteFile is true remove
|
|
|
|
* the source file. Returns @c true if the install succeeded.
|
|
|
|
*/
|
|
|
|
virtual bool installFile( const TQString &f, const bool deleteFile ) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notify the Pilot user that a conduit is running now.
|
|
|
|
* On real devices, this prints out (on screen) which database
|
|
|
|
* is now opened; useful for progress reporting.
|
|
|
|
*
|
|
|
|
* @return -1 on error
|
|
|
|
* @note the default implementation returns 0
|
|
|
|
*/
|
|
|
|
virtual int openConduit();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a file handle for raw operations. Not recommended.
|
|
|
|
* On links with no physical device backing, returns -1.
|
|
|
|
*
|
|
|
|
* @note the default implementation returns -1
|
|
|
|
*/
|
|
|
|
virtual int pilotSocket() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Actually write an entry to the device link. The message
|
|
|
|
* @p s must be guaranteed non-empty.
|
|
|
|
*/
|
|
|
|
virtual void addSyncLogEntryImpl( const TQString &s ) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* User information structure. Should be filled in when a sync
|
|
|
|
* starts, so that conduits can use the information.
|
|
|
|
*/
|
|
|
|
KPilotUser *fPilotUser;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* System information about the device. Filled in when the
|
|
|
|
* sync starts. Non-device links need to fake something.
|
|
|
|
*/
|
|
|
|
KPilotSysInfo *fPilotSysInfo;
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool fTickleDone;
|
|
|
|
TQThread *fTickleThread;
|
|
|
|
|
|
|
|
} ;
|
|
|
|
|
|
|
|
#endif
|