summaryrefslogtreecommitdiffstats
path: root/kpilot/lib/kpilotlink.h
diff options
context:
space:
mode:
Diffstat (limited to 'kpilot/lib/kpilotlink.h')
-rw-r--r--kpilot/lib/kpilotlink.h501
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