diff options
Diffstat (limited to 'kpilot/lib/kpilotlink.h')
-rw-r--r-- | kpilot/lib/kpilotlink.h | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/kpilot/lib/kpilotlink.h b/kpilot/lib/kpilotlink.h new file mode 100644 index 000000000..5c3865c3e --- /dev/null +++ b/kpilot/lib/kpilotlink.h @@ -0,0 +1,501 @@ +#ifndef _KPILOT_KPILOTLINK_H +#define _KPILOT_KPILOTLINK_H +/* KPilot +** +** Copyright (C) 1998-2001 by Dan Pilone +** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]> +** Copyright (C) 2006 Adriaan de Groot <[email protected]> +** +*/ + +/* +** 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 [email protected] +*/ + +#include <pi-dlp.h> + +#include <qobject.h> +#include <qvaluelist.h> + +/** @file +* Encapsulates all the communication with the handheld. Also +* does daemon-like polling of the handheld. Interesting status +* changes are signalled. +*/ + +class QThread; +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 QString &) +* # 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 QString &) 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 (libkabc 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 QObject +{ +Q_OBJECT +friend class SyncAction; +public: + /** A list of DBInfo structures. */ + typedef QValueList<struct DBInfo> DBInfoList; + + /** Constructor. Use reset() to start looking for a device. */ + KPilotLink( QObject *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 QString 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. + */ + QString 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 QString &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(QEvent *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 QStringList &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 QString &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 QString &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 QString &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 QString & ), 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 Qt 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 QString &); + + /** Signal that an error has occurred, for logging. */ + void logError(const QString &); + + /** + * 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 QString &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. + */ + QString 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 QString &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 QString &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; + QThread *fTickleThread; + +} ; + +#endif |