aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorFritz Elfert <felfert@to.com>2000-07-31 03:12:38 +0000
committerFritz Elfert <felfert@to.com>2000-07-31 03:12:38 +0000
commit7fb94ed43a814788cda019c1e77314abc1626339 (patch)
tree50b86a44e2809e6fbcdcd080f2a2dc4dbc37042e /lib
parentfbb17061d3c622f0786a5d9ad41e8ccd95ef706c (diff)
downloadplptools-7fb94ed43a814788cda019c1e77314abc1626339.tar.gz
plptools-7fb94ed43a814788cda019c1e77314abc1626339.tar.bz2
plptools-7fb94ed43a814788cda019c1e77314abc1626339.zip
Applied mjg-0.6 patch.
Started adding kdoc compliant documentation comments. Added PsiTime
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am6
-rw-r--r--lib/bufferarray.cc22
-rw-r--r--lib/bufferarray.h137
-rw-r--r--lib/bufferstore.cc46
-rw-r--r--lib/bufferstore.h223
-rw-r--r--lib/ppsocket.cc4
-rw-r--r--lib/psitime.cc117
-rw-r--r--lib/psitime.h198
-rw-r--r--lib/rfsv.h64
-rw-r--r--lib/rfsv16.cc432
-rw-r--r--lib/rfsv16.h3
-rw-r--r--lib/rfsv32.cc102
-rw-r--r--lib/rfsv32.h3
-rw-r--r--lib/rpcs.cc138
-rw-r--r--lib/rpcs.h306
-rw-r--r--lib/rpcs16.cc2
-rw-r--r--lib/rpcs16.h2
-rw-r--r--lib/rpcs32.cc125
-rw-r--r--lib/rpcs32.h8
-rw-r--r--lib/rpcsfactory.cc9
-rw-r--r--lib/rpcsfactory.h28
21 files changed, 1640 insertions, 335 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 08df502..ec7a840 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,9 +1,9 @@
lib_LTLIBRARIES = libplp.la
-libplp_la_LDFLAGS = --debug -version-info 1:0:0
+libplp_la_LDFLAGS = --debug -version-info 1:1:0
libplp_la_SOURCES = bufferarray.cc bufferstore.cc iowatch.cc ppsocket.cc \
rfsv16.cc rfsv32.cc rfsvfactory.cc log.cc rfsv.cc rpcs32.cc rpcs16.cc \
- rpcs.cc rpcsfactory.cc
+ rpcs.cc rpcsfactory.cc psitime.cc
EXTRA_DIST = bool.h bufferarray.h bufferstore.h iowatch.h ppsocket.h \
rfsv.h rfsv16.h rfsv32.h rfsvfactory.h log.h rpcs32.h rpcs16.h rpcs.h \
- rpcsfactory.h
+ rpcsfactory.h psitime.h
diff --git a/lib/bufferarray.cc b/lib/bufferarray.cc
index 4e922ed..77a08c6 100644
--- a/lib/bufferarray.cc
+++ b/lib/bufferarray.cc
@@ -45,11 +45,11 @@ bufferArray::bufferArray(const bufferArray & a)
bufferArray::~bufferArray()
{
- delete[]buff;
+ delete []buff;
}
bufferStore bufferArray::
-popBuffer()
+pop()
{
bufferStore ret;
if (len > 0) {
@@ -63,7 +63,7 @@ popBuffer()
}
void bufferArray::
-pushBuffer(const bufferStore & b)
+append(const bufferStore & b)
{
if (len == lenAllocd) {
lenAllocd += ALLOC_MIN;
@@ -71,7 +71,7 @@ pushBuffer(const bufferStore & b)
for (long i = 0; i < len; i++) {
nb[i] = buff[i];
}
- delete[]buff;
+ delete []buff;
buff = nb;
}
buff[len++] = b;
@@ -84,7 +84,7 @@ push(const bufferStore & b)
lenAllocd += ALLOC_MIN;
bufferStore *nb = new bufferStore[lenAllocd];
for (long i = len; i > 0; i--) {
- nb[i] = buff[i-1];
+ nb[i] = buff[i - 1];
}
nb[0] = b;
delete[]buff;
@@ -92,18 +92,6 @@ push(const bufferStore & b)
len++;
}
-bufferStore bufferArray::
-pop()
-{
- return popBuffer();
-}
-
-void bufferArray::
-append(const bufferStore & b)
-{
- pushBuffer(b);
-}
-
long bufferArray::
length(void)
{
diff --git a/lib/bufferarray.h b/lib/bufferarray.h
index fbf26f1..7389ab6 100644
--- a/lib/bufferarray.h
+++ b/lib/bufferarray.h
@@ -4,35 +4,120 @@
#include "bool.h"
class bufferStore;
+/**
+ * An array of bufferStores
+ */
class bufferArray {
- public:
- bufferArray();
- bufferArray(const bufferArray &a);
- ~bufferArray();
- bufferArray &operator =(const bufferArray &a);
- bool empty() const;
-
- // this is NOT a real push as with a FIFO but
- // appends the bufferStore.
- void pushBuffer(const bufferStore& b);
- bufferStore popBuffer(void);
-
- // new API (push() now behaves like a FIFO, more operators
- bufferStore &operator [](const unsigned long index);
- bufferArray &operator +(const bufferStore &); // append
- bufferArray &operator +(const bufferArray &); // append
- bufferArray &operator +=(const bufferStore &b); // append
- bufferStore pop(void);
- void push(const bufferStore& b);
- void append(const bufferStore& b);
- long length(void);
- void clear(void);
+public:
+ /**
+ * constructs a new bufferArray.
+ * A minimum of @ref ALLOC_MIN
+ * elements is allocated.
+ */
+ bufferArray();
+
+ /**
+ * Constructs a new bufferArray.
+ *
+ * @param a The initial contents for this array.
+ */
+ bufferArray(const bufferArray &a);
+
+ /**
+ * Destroys the bufferArray.
+ */
+ ~bufferArray();
+
+ /**
+ * Copys the bufferArray.
+ */
+ bufferArray &operator =(const bufferArray &a);
+
+ /**
+ * Checks if this bufferArray is empty.
+ *
+ * @return true if the bufferArray is empty.
+ */
+ bool empty() const;
+
+ /**
+ * Retrieves the bufferStore at given index.
+ *
+ * @return The bufferStore at index.
+ */
+ bufferStore &operator [](const unsigned long index);
+
+ /**
+ * Appends a bufferStore.
+ */
+ bufferArray &operator +(const bufferStore &);
+
+ /**
+ * Concatenates two bufferArrays.
+ */
+ bufferArray &operator +(const bufferArray &);
+
+ /**
+ * Appends a bufferStore.
+ */
+ bufferArray &operator +=(const bufferStore &b);
+
+ /**
+ * Removes the first bufferStore.
+ *
+ * @return The removed bufferStore.
+ */
+ bufferStore pop(void);
+
+ /**
+ * Inserts a bufferStore at index 0.
+ *
+ * @param b The bufferStore to be inserted.
+ */
+ void push(const bufferStore& b);
+
+ /**
+ * Appends a bufferStore.
+ *
+ * @param b The bufferStore to be appended.
+ */
+ void append(const bufferStore& b);
+
+ /**
+ * Evaluates the current length.
+ *
+ * @return The current number of bufferStores
+ */
+ long length(void);
+
+ /**
+ * Empties the bufferArray.
+ */
+ void clear(void);
private:
- static const long ALLOC_MIN = 5;
- long len;
- long lenAllocd;
- bufferStore* buff;
+ /**
+ * Minimum number of bufferStores to
+ * allocate.
+ */
+ static const long ALLOC_MIN = 5;
+
+ /**
+ * The current number of bufferStores in
+ * this bufferArray.
+ */
+ long len;
+
+ /**
+ * The current number of bufferStores
+ * allocated.
+ */
+ long lenAllocd;
+
+ /**
+ * The content.
+ */
+ bufferStore* buff;
};
inline bool bufferArray::empty() const { return len == 0; }
diff --git a/lib/bufferstore.cc b/lib/bufferstore.cc
index 842e666..7f2b49d 100644
--- a/lib/bufferstore.cc
+++ b/lib/bufferstore.cc
@@ -22,28 +22,30 @@
#include <stream.h>
// That should be iostream.h, but it won't build on Sun WorkShop C++ 5.0
#include <iomanip.h>
+#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include "bufferstore.h"
bufferStore::bufferStore() {
lenAllocd = 0;
- buff = NULL;
+ buff = 0L;
len = 0;
start = 0;
}
bufferStore::bufferStore(const bufferStore &a) {
lenAllocd = (a.getLen() > MIN_LEN) ? a.getLen() : MIN_LEN;
- buff = new unsigned char [lenAllocd];
+ buff = (unsigned char *)malloc(lenAllocd);
len = a.getLen();
memcpy(buff, a.getString(0), len);
start = 0;
}
-bufferStore::bufferStore(const unsigned char*_buff, long _len) {
+bufferStore::bufferStore(const unsigned char *_buff, long _len) {
lenAllocd = (_len > MIN_LEN) ? _len : MIN_LEN;
- buff = new unsigned char [lenAllocd];
+ buff = (unsigned char *)malloc(lenAllocd);
len = _len;
memcpy(buff, _buff, len);
start = 0;
@@ -54,6 +56,7 @@ bufferStore &bufferStore::operator =(const bufferStore &a) {
len = a.getLen();
memcpy(buff, a.getString(0), len);
start = 0;
+ return *this;
}
void bufferStore::init() {
@@ -69,7 +72,8 @@ void bufferStore::init(const unsigned char*_buff, long _len) {
}
bufferStore::~bufferStore() {
- delete [] buff;
+ if (buff != 0L)
+ free(buff);
}
unsigned long bufferStore::getLen() const {
@@ -92,23 +96,26 @@ unsigned int bufferStore::getDWord(long pos) const {
}
const char* bufferStore::getString(long pos) const {
- return (const char*)buff+pos+start;
+ return (const char*)buff + pos + start;
}
ostream &operator<<(ostream &s, const bufferStore &m) {
- {
- for (int i = m.start; i < m.len; i++)
+ // save stream flags
+ ostream::fmtflags old = s.flags();
+
+ for (int i = m.start; i < m.len; i++)
s << hex << setw(2) << setfill('0') << (int)m.buff[i] << " ";
- }
+
+ // restore stream flags
+ s.flags(old);
s << "(";
- {
- for (int i = m.start; i < m.len; i++) {
- unsigned char c = m.buff[i];
- if (c>=' ' && c <= 'z') s << c;
- }
+
+ for (int i = m.start; i < m.len; i++) {
+ unsigned char c = m.buff[i];
+ s << (unsigned char)(isprint(c) ? c : '.');
}
- s<< ")" << dec << setw(0);
- return s;
+
+ return s << ")";
}
void bufferStore::discardFirstBytes(int n) {
@@ -119,12 +126,9 @@ void bufferStore::discardFirstBytes(int n) {
void bufferStore::checkAllocd(long newLen) {
if (newLen >= lenAllocd) {
do {
- lenAllocd = (lenAllocd < MIN_LEN)?MIN_LEN:(lenAllocd*2);
+ lenAllocd = (lenAllocd < MIN_LEN) ? MIN_LEN : (lenAllocd * 2);
} while (newLen >= lenAllocd);
- unsigned char* newBuff = new unsigned char [lenAllocd];
- memcpy(&newBuff[start], &buff[start], len - start);
- delete [] buff;
- buff = newBuff;
+ buff = (unsigned char *)realloc(buff, lenAllocd);
}
}
diff --git a/lib/bufferstore.h b/lib/bufferstore.h
index df216c0..cad32fa 100644
--- a/lib/bufferstore.h
+++ b/lib/bufferstore.h
@@ -4,48 +4,205 @@
#include "bool.h"
class ostream;
+/**
+ * A generic container for an array of bytes.
+ *
+ * bufferStore provides an array of bytes which
+ * can be accessed using various types.
+ */
class bufferStore {
public:
- bufferStore();
- bufferStore(const unsigned char *, long);
- ~bufferStore();
- bufferStore(const bufferStore &);
- bufferStore &operator =(const bufferStore &);
-
- // Reading Utils
- unsigned long getLen() const;
- unsigned char getByte(long pos) const;
- unsigned int getWord(long pos) const;
- unsigned int getDWord(long pos) const;
- const char* getString(long pos=0) const;
- void discardFirstBytes(int);
- friend ostream &operator<<(ostream &, const bufferStore &);
- bool empty() const;
-
- // Writing utils
- void init();
- void init(const unsigned char*, long);
- void addByte(unsigned char);
- void addWord(int);
- void addDWord(long);
- void addString(const char*);
- void addStringT(const char*);
- void addBytes(const unsigned char*, int);
- void addBuff(const bufferStore &, long maxLen=-1);
+ /**
+ * Constructs a new bufferStore.
+ */
+ bufferStore();
+
+ /**
+ * Constructs a new bufferStore and
+ * initializes its content.
+ *
+ * @param buf Pointer to data for initialization.
+ * @param len Length of data for initialization.
+ */
+ bufferStore(const unsigned char *, long);
+
+ /**
+ * Destroys a bufferStore instance.
+ */
+ ~bufferStore();
+
+ /**
+ * Constructs a new bufferStore and
+ * initializes its content.
+ *
+ * @param b A bufferStore, whose content is
+ * used for initialization.
+ */
+ bufferStore(const bufferStore &);
+
+ /**
+ * Copies a bufferStore.
+ */
+ bufferStore &operator =(const bufferStore &);
+
+ /**
+ * Retrieves the length of a bufferStore.
+ *
+ * @returns The current length of the contents
+ * in bytes.
+ */
+ unsigned long getLen() const;
+
+ /**
+ * Retrieves the byte at index <em>pos</em>.
+ *
+ * @param pos The index of the byte to retrieve.
+ *
+ * @returns The value of the byte at index <em>pos</em>
+ */
+ unsigned char getByte(long pos) const;
+
+ /**
+ * Retrieves the word at index <em>pos</em>.
+ *
+ * @param pos The index of the word to retrieve.
+ *
+ * @returns The value of the word at index <em>pos</em>
+ */
+ unsigned int getWord(long pos) const;
+
+ /**
+ * Retrieves the dword at index <em>pos</em>.
+ *
+ * @param pos The index of the dword to retrieve.
+ *
+ * @returns The value of the dword at index <em>pos</em>
+ */
+ unsigned int getDWord(long pos) const;
+
+ /**
+ * Retrieves the characters at index <em>pos</em>.
+ *
+ * @param pos The index of the characters to retrieve.
+ *
+ * @returns A pointer to characters at index <em>pos</em>
+ */
+ const char* getString(long pos=0) const;
+
+ /**
+ * Removes bytes from the start of the buffer.
+ *
+ * @param len Number of bytes to remove.
+ */
+ void discardFirstBytes(int);
+
+ /**
+ * Prints a dump of the content.
+ *
+ * Mainly used for debugging purposes.
+ *
+ * @param s The stream to write to.
+ * @param b The bufferStore do be dumped.
+ *
+ * @returns The stream.
+ */
+ friend ostream &operator<<(ostream &, const bufferStore &);
+
+ /**
+ * Tests if the bufferStore is empty.
+ *
+ * @returns true, if the bufferStore is empty.
+ * false, if it contains data.
+ */
+ bool empty() const;
+
+ /**
+ * Initializes the bufferStore.
+ *
+ * All data is removed, the length is
+ * reset to 0.
+ */
+ void init();
+
+ /**
+ * Initializes the bufferStore with
+ * a given data.
+ *
+ * @param buf Pointer to data to initialize from.
+ * @param len Length of data.
+ */
+ void init(const unsigned char*, long);
+
+ /**
+ * Appends a byte to the content of this instance.
+ *
+ * @param c The byte to append.
+ */
+ void addByte(unsigned char);
+
+ /**
+ * Appends a word to the content of this instance.
+ *
+ * @param w The word to append.
+ */
+ void addWord(int);
+
+ /**
+ * Appends a dword to the content of this instance.
+ *
+ * @param dw The dword to append.
+ */
+ void addDWord(long);
+
+ /**
+ * Appends a string to the content of this instance.
+ *
+ * The trailing zero byte is <em>not</em> copied
+ * to the content.
+ *
+ * @param s The string to append.
+ */
+ void addString(const char*);
+
+ /**
+ * Appends a string to the content of this instance.
+ *
+ * The trailing zero byte <em>is</em> copied
+ * to the content.
+ *
+ * @param s The string to append.
+ */
+ void addStringT(const char*);
+
+ /**
+ * Appends data to the content of this instance.
+ *
+ * @param buf The data to append.
+ * @param len Length of data.
+ */
+ void addBytes(const unsigned char*, int);
+
+ /**
+ * Appends data to the content of this instance.
+ *
+ * @param b The bufferStore whose content to append.
+ * @param maxLen Length of content.
+ */
+ void addBuff(const bufferStore &, long maxLen=-1);
private:
- void checkAllocd(long newLen);
+ void checkAllocd(long newLen);
- long len;
- long lenAllocd;
- long start;
- unsigned char* buff;
+ long len;
+ long lenAllocd;
+ long start;
+ unsigned char* buff;
- enum c { MIN_LEN = 300 };
+ enum c { MIN_LEN = 300 };
};
inline bool bufferStore::empty() const {
- return (len-start) == 0;
+ return (len-start) == 0;
}
#endif
diff --git a/lib/ppsocket.cc b/lib/ppsocket.cc
index cb04919..1249f18 100644
--- a/lib/ppsocket.cc
+++ b/lib/ppsocket.cc
@@ -181,7 +181,11 @@ listen(char *Host, int Port)
ppsocket *ppsocket::
accept(char *Peer, int MaxLen)
{
+#ifdef sun
+ int len;
+#else
socklen_t len;
+#endif
ppsocket *accepted;
char *peer;
diff --git a/lib/psitime.cc b/lib/psitime.cc
new file mode 100644
index 0000000..95ba6da
--- /dev/null
+++ b/lib/psitime.cc
@@ -0,0 +1,117 @@
+
+#include "psitime.h"
+#include <stdlib.h>
+
+PsiTime::PsiTime(psi_timeval *_ptv, psi_timezone *_ptz) {
+ if (_ptv != 0L)
+ ptv = *_ptv;
+ if (_ptz != 0L) {
+ ptz = *_ptz;
+ ptzValid = true;
+ } else
+ ptzValid = false;
+ /* get our own timezone */
+ gettimeofday(NULL, &utz);
+ psi2unix();
+}
+
+PsiTime::~PsiTime() {
+}
+
+void PsiTime::setUnixTime(struct timeval *_utv) {
+ if (_utv != 0L)
+ utv = *_utv;
+ unix2psi();
+}
+
+void PsiTime::setUnixNow(void) {
+ gettimeofday(&utv, &utz);
+ unix2psi();
+}
+
+
+void PsiTime::setPsiTime(psi_timeval *_ptv) {
+ if (_ptv != 0L)
+ ptv = *_ptv;
+ psi2unix();
+}
+
+void PsiTime::setPsiZone(psi_timezone *_ptz) {
+ if (_ptz != 0L) {
+ ptz = *_ptz;
+ ptzValid = true;
+ }
+ psi2unix();
+}
+
+struct timeval &PsiTime::getTimeval(void) {
+ return utv;
+}
+
+time_t PsiTime::getTime(void) {
+ return utv.tv_sec;
+}
+
+psi_timeval &PsiTime::getPsiTimeval(void) {
+ return ptv;
+}
+
+ostream &operator<<(ostream &s, const PsiTime &t) {
+ const char *fmt = "%c";
+ char buf[100];
+ strftime(buf, sizeof(buf), fmt, localtime(&t.utv.tv_sec));
+ s << buf;
+ return s;
+}
+
+/**
+ * The difference between
+ * EPOC epoch (01.01.0001 00:00:00)
+ * and Unix epoch (01.01.1970 00:00:00)
+ * in microseconds.
+ */
+#define EPOCH_DIFF 0x00dcddb30f2f8000ULL
+
+static unsigned long long
+evalOffset(psi_timezone ptz, bool valid) {
+ unsigned long long offset = 0;
+
+ if (valid) {
+ offset = ptz.utc_offset;
+ if ((ptz.dst_zones & 0x40000000) || (ptz.dst_zones & ptz.home_zone))
+ offset += 3600;
+ } else {
+ const char *offstr = getenv("PSI_TZ");
+ if (offstr != 0L) {
+ char *err = 0L;
+ offset = strtoul(offstr, &err, 0);
+ if (err != 0L)
+ offset = 0;
+ }
+ }
+ offset *= 1000000;
+ return offset;
+}
+
+void PsiTime::psi2unix(void) {
+ unsigned long long micro = ptv.tv_high;
+ micro = (micro << 32) | ptv.tv_low;
+
+ /* Substract Psion's idea of UTC offset */
+ micro -= evalOffset(ptz, ptzValid);
+ micro -= EPOCH_DIFF;
+
+ utv.tv_sec = micro / 1000000;
+ utv.tv_usec = micro % 1000000;
+}
+
+void PsiTime::unix2psi(void) {
+ unsigned long long micro = utv.tv_sec * 1000000 + utv.tv_usec;
+
+ /* Add Psion's idea of UTC offset */
+ micro += EPOCH_DIFF;
+ micro += evalOffset(ptz, ptzValid);
+
+ ptv.tv_low = micro & 0x0ffffffff;
+ ptv.tv_high = (micro >> 32) & 0x0ffffffff;
+}
diff --git a/lib/psitime.h b/lib/psitime.h
new file mode 100644
index 0000000..6946fc1
--- /dev/null
+++ b/lib/psitime.h
@@ -0,0 +1,198 @@
+#ifndef _PSITIME_H_
+#define _PSITIME_H_
+
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <ostream.h>
+
+/**
+ * Holds a Psion time value.
+ * Psion time values are 64 bit
+ * integers describing the time
+ * since 01.01.0001 in microseconds.
+ */
+typedef struct psi_timeval_t {
+ /**
+ * Prints a psi_timeval in human readable format.
+ */
+ friend ostream &operator<<(ostream &o, const psi_timeval_t &ptv) {
+ ostream::fmtflags old = o.flags();
+ unsigned long long micro = ptv.tv_high;
+ micro = (micro << 32) | ptv.tv_low;
+ micro /= 1000000;
+ int s = micro % 60;
+ micro /= 60;
+ int m = micro % 60;
+ micro /= 60;
+ int h = micro % 24;
+ micro /= 24;
+ int d = micro % 365;
+ micro /= 365;
+ int y = micro;
+ o << dec;
+ if (y > 0)
+ o << y << " year" << ((y > 1) ? "s " : " ");
+ if (d > 0)
+ o << d << " day" << ((d > 1) ? "s " : " ");
+ if (h > 0)
+ o << h << " hour" << ((h != 1) ? "s " : " ");
+ if (m > 0)
+ o << m << " minute" << ((m != 1) ? "s " : " ");
+ o << s << " second" << ((s != 1) ? "s" : "");
+ o.flags(old);
+ return o;
+ }
+ /**
+ * The lower 32 bits
+ */
+ unsigned long tv_low;
+ /**
+ * The upper 32 bits
+ */
+ unsigned long tv_high;
+} psi_timeval;
+
+/**
+ * holds a Psion time zone description.
+ */
+typedef struct psi_timezone_t {
+ friend ostream &operator<<(ostream &s, const psi_timezone_t &ptz) {
+ ostream::fmtflags old = s.flags();
+ int h = ptz.utc_offset / 3600;
+ int m = ptz.utc_offset % 3600;
+ s << "offs: " << dec << h << "h";
+ if (m != 0)
+ s << ", " << m << "m";
+ s.flags(old);
+ return s;
+ }
+ unsigned long utc_offset;
+ unsigned long dst_zones;
+ unsigned long home_zone;
+} psi_timezone;
+
+/**
+ * Psion time related utility class.
+ *
+ * PsiTime provides easy access to the time format, used
+ * when communicating with a Psion. Internally, the time
+ * is always normalized to GMT. The time value can be set
+ * and retrieved in both Unix and Psion formats. This
+ * allows easy conversion between both formats.
+ * NOTE: For proper conversion, the current timezone of
+ * the Psion has to be set. For EPOC devices, the
+ * timezone can be evaluated using
+ * @ref rpcs::getMachineInfo. For SIBO devices,
+ * unfortunately there is no known method of retrieving
+ * this information. Therefore, if the timezone is
+ * <em>not</em> set, a fallback using the environment
+ * variable <em>PSI_TZ</em> is provided. Users should
+ * set this variable to the offset of their time zone
+ * in seconds.
+ */
+class PsiTime {
+public:
+ /**
+ * Contructs a new instance.
+ *
+ * @param _ptv A Psion time value for initialization.
+ * @param _ptz A Psion timezone for initialization.
+ */
+ PsiTime(psi_timeval *_ptv = 0L, psi_timezone *_ptz = 0L);
+
+ /**
+ * Constructs a new instance.
+ *
+ * @param _utv A Unix time value for initialization.
+ * @param _utz A Unix timezone for initialization.
+ */
+ PsiTime(struct timeval *_utv = 0L, struct timezone *_utz = 0L);
+
+ /**
+ * Destroys the instance.
+ */
+ ~PsiTime();
+
+ /**
+ * Modifies the value of this instance.
+ *
+ * @param _ptv The new Psion time representation.
+ */
+ void setPsiTime(psi_timeval *_ptv);
+
+ /**
+ * Sets the Psion time zone of this instance.
+ *
+ * @param _ptz The new Psion time zone.
+ */
+ void setPsiZone(psi_timezone *_ptz);
+
+ /**
+ * Sets the value of this instance.
+ *
+ * @param _utv The new Unix time representation.
+ */
+ void setUnixTime(struct timeval *_utv);
+
+ /**
+ * Sets the value of this instance to the
+ * current time of the Unix machine.
+ */
+ void setUnixNow(void);
+
+ /**
+ * Retrieves the instance's current value
+ * in Unix time format.
+ *
+ * @returns The instance's current time as Unix struct timeval.
+ */
+ struct timeval &getTimeval(void);
+
+ /**
+ * Retrieves the instance's current value
+ * in Unix time format.
+ *
+ * @returns The instance's current time as Unix time_t.
+ */
+ time_t getTime(void);
+
+ /**
+ * Retrieves the instance's current value
+ * in Psion time format.
+ *
+ * @returns The instance's current time a Psion struct psi_timeval_t.
+ */
+ psi_timeval &getPsiTimeval(void);
+
+ /**
+ * Prints the instance's value in human readable format.
+ * This function uses the current locale setting for
+ * formatting the time.
+ *
+ * @param s The stream to be written.
+ * @param t The instance whose value should be displayed.
+ *
+ * @returns The stream.
+ */
+ friend ostream &operator<<(ostream &s, const PsiTime &t);
+
+ enum zone {
+ PSI_TZ_NONE = 0,
+ PSI_TZ_EUROPEAN = 1,
+ PSI_TZ_NORTHERN = 2,
+ PSI_TZ_SOUTHERN = 4,
+ PSI_TZ_HOME = 0x40000000,
+ };
+
+private:
+ void psi2unix(void);
+ void unix2psi(void);
+
+ psi_timeval ptv;
+ psi_timezone ptz;
+ struct timeval utv;
+ struct timezone utz;
+ bool ptzValid;
+};
+#endif
diff --git a/lib/rfsv.h b/lib/rfsv.h
index e6006ef..888db8a 100644
--- a/lib/rfsv.h
+++ b/lib/rfsv.h
@@ -5,12 +5,29 @@ class ppsocket;
class bufferStore;
class bufferArray;
-#define RFSV_SENDLEN 2000
+const unsigned long RFSV_SENDLEN = 2000;
+/**
+ * Defines the callback procedure for
+ * progress indication of copy operations.
+ */
typedef int (*cpCallback_t)(long);
// Abstract base class of RFSV ; 16-bit and 32-bit variants implement this
// interface
+/**
+ * Access remote file services of a Psion.
+ *
+ * rfsv provides an API for accessing file services
+ * of a Psion connected via ncpd. This class defines the
+ * interface and a small amount of common constants and
+ * methods. The majority of implementation is provided
+ * by @ref rfsv32 and @ref rfsv16, which implement the
+ * variations of the protocol for EPOC and SIBO respectively.
+ * Usually, the class @ref rfsvfactory is used to instantiate
+ * the correct variant depending on the remote machine,
+ * currently connected.
+ */
class rfsv {
public:
virtual ~rfsv() {}
@@ -46,20 +63,32 @@ class rfsv {
virtual long rename(const char *, const char *) = 0;
virtual long remove(const char *) = 0;
+ virtual long attr2std(long) = 0;
+ virtual long std2attr(long) = 0;
+
char *opErr(long);
+ /**
+ * The kown modes for seek.
+ */
enum seek_mode {
PSI_SEEK_SET = 1,
PSI_SEEK_CUR = 2,
PSI_SEEK_END = 3
};
+ /**
+ * The known modes for file open.
+ */
enum open_flags {
PSI_O_RDONLY = 00,
PSI_O_WRONLY = 01,
PSI_O_RDWR = 02,
};
+ /**
+ * The known modes for file creation.
+ */
enum open_mode {
PSI_O_CREAT = 0100,
PSI_O_EXCL = 0200,
@@ -67,6 +96,9 @@ class rfsv {
PSI_O_APPEND = 02000,
};
+ /**
+ * The known error codes.
+ */
enum errs {
E_PSI_GEN_NONE = 0,
E_PSI_GEN_FAIL = -1,
@@ -145,6 +177,36 @@ class rfsv {
// Special error code for "Operation not permitted in RFSV16"
E_PSI_NOT_SIBO = -200
};
+
+ /**
+ * The known file attributes
+ */
+ enum file_attribs {
+ /**
+ * Attributes, valid on both EPOC and SIBO.
+ */
+ PSI_A_RDONLY = 0x0001,
+ PSI_A_HIDDEN = 0x0002,
+ PSI_A_SYSTEM = 0x0004,
+ PSI_A_DIR = 0x0008,
+ PSI_A_ARCHIVE = 0x0010,
+ PSI_A_VOLUME = 0x0020,
+
+ /**
+ * Attributes, valid on EPOC only.
+ */
+ PSI_A_NORMAL = 0x0040,
+ PSI_A_TEMP = 0x0080,
+ PSI_A_COMPRESSED = 0x0100,
+
+ /**
+ * Attributes, valid on SIBO only.
+ */
+ PSI_A_READ = 0x0200,
+ PSI_A_EXEC = 0x0400,
+ PSI_A_STREAM = 0x0800,
+ PSI_A_TEXT = 0x1000
+ };
};
#endif
diff --git a/lib/rfsv16.cc b/lib/rfsv16.cc
index 9ee24f2..f71be9f 100644
--- a/lib/rfsv16.cc
+++ b/lib/rfsv16.cc
@@ -37,6 +37,8 @@
#include "ppsocket.h"
#include "bufferarray.h"
+#define RFSV16_MAXDATALEN 852 // 640
+
rfsv16::rfsv16(ppsocket *_skt) : serNum(0)
{
skt = _skt;
@@ -57,7 +59,6 @@ rfsv16::~rfsv16()
void rfsv16::
reconnect()
{
-cerr << "rfsv16::reconnect" << endl;
skt->closeSocket();
skt->reconnect();
serNum = 0;
@@ -68,7 +69,6 @@ cerr << "rfsv16::reconnect" << endl;
void rfsv16::
reset()
{
-cerr << "rfsv16::reset" << endl;
bufferStore a;
status = E_PSI_FILE_DISC;
a.addStringT(getConnectName());
@@ -91,7 +91,7 @@ getStatus()
const char *rfsv16::
getConnectName()
{
- return "SYS$RFSV.*";
+ return "SYS$RFSV";
}
int rfsv16::
@@ -148,14 +148,10 @@ fopen(long attr, const char *name, long &handle)
return E_PSI_FILE_DISC;
long res = getResponse(a);
- // cerr << "fopen, getword 0 is " << hex << setw(2) << a.getWord(0) << endl;
- // cerr << "fopen, getlen is " << hex << setw(2) << a.getLen() << endl;
- // cerr << "fopen, res is " << hex << setw(2) << res << endl;
- if (!res && a.getLen() == 4 && a.getWord(0) == 0) {
- handle = (long)a.getWord(2);
+ if (res == 0) {
+ handle = (long)a.getWord(0);
return 0;
}
- // cerr << "fopen: Unknown response (" << attr << "," << name << ") " << a <<endl;
return res;
}
@@ -163,24 +159,38 @@ fopen(long attr, const char *name, long &handle)
long rfsv16::
mktemp(long *handle, char *tmpname)
{
-cerr << "rfsv16::mktemp ***" << endl;
- return 0;
+ bufferStore a;
+
+ // FIXME: anything that calls fopen should NOT do the name
+ // conversion - it's just done here.
+
+ a.addWord(P_FUNIQUE);
+ a.addString("TMP");
+ a.addByte(0x00); // Needs to be manually Null-Terminated.
+ if (!sendCommand(OPENUNIQUE, a))
+ return E_PSI_FILE_DISC;
+
+ long res = getResponse(a);
+ if (res == 0) {
+ *handle = a.getWord(0);
+ strcpy(tmpname, a.getString(2));
+ return 0;
+ }
+ return res;
}
// internal and external
long rfsv16::
fcreatefile(long attr, const char *name, long &handle)
{
-cerr << "rfsv16::fcreatefile ***" << endl;
- return 0;
+ return fopen(attr | P_FCREATE, name, handle);
}
// this is internal - not used by plpnfsd, unlike fcreatefile
long rfsv16::
freplacefile(long attr, const char *name, long &handle)
{
-cerr << "rfsv16::freplacefile ***" << endl;
- return 0;
+ return fopen(attr | P_FREPLACE, name, handle);
}
// internal
@@ -198,11 +208,7 @@ fclose(long fileHandle)
a.addWord(fileHandle & 0xFFFF);
if (!sendCommand(FCLOSE, a))
return E_PSI_FILE_DISC;
- long res = getResponse(a);
- if (!res && a.getLen() == 2)
- return (long)a.getWord(0);
- cerr << "fclose: Unknown response "<< a <<endl;
- return 1;
+ return getResponse(a);
}
long rfsv16::
@@ -224,7 +230,7 @@ dir(const char *dirName, bufferArray * files)
res = getResponse(a);
if (res)
break;
- a.discardFirstBytes(4); // Don't know what these mean!
+ a.discardFirstBytes(2); // Don't know what these mean!
while (a.getLen() > 16) {
int version = a.getWord(0);
if (version != 2) {
@@ -242,7 +248,7 @@ dir(const char *dirName, bufferArray * files)
temp.addDWord(size);
temp.addDWord((long)status);
temp.addStringT(s);
- files->pushBuffer(temp);
+ files->append(temp);
}
}
if ((short int)res == E_PSI_FILE_EOF)
@@ -300,15 +306,13 @@ cerr << "rfsv16::fgetmtime" << endl;
return E_PSI_FILE_DISC;
long res = getResponse(a);
- if (res != 0)
+ if (res != 0) {
+ cerr << "fgetmtime: Error " << res << " on file " << name << endl;
return res;
- if (a.getLen() == 2) {
- cerr << "fgetmtime: Error " << a.getWord(0) << " on file " << name << endl;
- return 1;
}
- else if (a.getLen() == 18 && a.getWord(0) == 0) {
- *mtime = a.getDWord(10);
- return a.getWord(0);
+ else if (a.getLen() == 16) {
+ *mtime = a.getDWord(8);
+ return res;
}
cerr << "fgetmtime: Unknown response (" << name << ") " << a <<endl;
return 1;
@@ -338,15 +342,13 @@ fgetattr(const char *name, long *attr)
return E_PSI_FILE_DISC;
long res = getResponse(a);
- if (res != 0)
+ if (res != 0) {
+ cerr << "fgetattr: Error " << res << " on file " << name << endl;
return res;
- if (a.getLen() == 2) {
- cerr << "fgetattr: Error " << a.getWord(0) << " on file " << name << endl;
- return 1;
}
- else if (a.getLen() == 18 && a.getWord(0) == 0) {
- *attr = (long)(a.getWord(4));
- return a.getWord(0);
+ else if (a.getLen() == 16) {
+ *attr = (long)(a.getWord(2));
+ return res;
}
cerr << "fgetattr: Unknown response (" << name << ") " << a <<endl;
return 1;
@@ -366,17 +368,15 @@ fgeteattr(const char *name, long *attr, long *size, long *time)
return E_PSI_FILE_DISC;
long res = getResponse(a);
- if (res != 0)
- return res;
- if (a.getLen() == 2) {
+ if (res != 0) {
cerr << "fgeteattr: Error " << a.getWord(0) << " on file " << name << endl;
- return 1;
+ return res;
}
- else if (a.getLen() == 18 && a.getWord(0) == 0) {
- *attr = (long)(a.getWord(4));
- *size = a.getDWord(6);
- *time = a.getDWord(10);
- return a.getWord(0);
+ else if (a.getLen() == 16) {
+ *attr = (long)(a.getWord(2));
+ *size = a.getDWord(4);
+ *time = a.getDWord(8);
+ return res;
}
cerr << "fgeteattr: Unknown response (" << name << ") " << a <<endl;
return 1;
@@ -429,7 +429,7 @@ dircount(const char *name, long *count)
res = getResponse(a);
if (res)
break;
- a.discardFirstBytes(4); // Don't know what these mean!
+ a.discardFirstBytes(2); // Don't know what these mean!
while (a.getLen() > 16) {
int version = a.getWord(0);
if (version != 2) {
@@ -475,7 +475,7 @@ devlist(long *devbits)
// Find the drive to FOPEN
char name[4] = { 'x', ':', '\\', '\0' } ;
- a.discardFirstBytes(8); // Result, fsys, dev, path, file, file, ending, flag
+ a.discardFirstBytes(6); // Result, fsys, dev, path, file, file, ending, flag
/* This leaves R E M : : M : \ */
name[0] = (char) a.getByte(5); // the M
long status = fopen(P_FDEVICE, name, fileHandle);
@@ -491,7 +491,6 @@ devlist(long *devbits)
res = getResponse(a);
if (res)
break;
- a.discardFirstBytes(2); // Result
int version = a.getWord(0);
if (version != 2) {
cerr << "devlist: not version 2" << endl;
@@ -551,7 +550,6 @@ devinfo(int devnum, long *vfree, long *vtotal, long *vattr,
// cerr << "devinfo STATUSDEVICE res is " << dec << (signed short int) res << endl;
return NULL;
}
- a.discardFirstBytes(2); // Result
int type = a.getWord(2);
int changeable = a.getWord(4);
long size = a.getDWord(6);
@@ -571,14 +569,24 @@ devinfo(int devnum, long *vfree, long *vtotal, long *vattr,
bool rfsv16::
sendCommand(enum commands cc, bufferStore & data)
{
+ if (status == E_PSI_FILE_DISC) {
+ reconnect();
+ if (status == E_PSI_FILE_DISC)
+ return FALSE;
+ }
+
bool result;
bufferStore a;
a.addWord(cc);
a.addWord(data.getLen());
a.addBuff(data);
result = skt->sendBufferStore(a);
+ if (!result) {
+ reconnect();
+ result = skt->sendBufferStore(a);
if (!result)
status = E_PSI_FILE_DISC;
+ }
return result;
}
@@ -589,17 +597,22 @@ getResponse(bufferStore & data)
// getWord(2) is the size field
// which is the body of the response not counting the command (002a) and
// the size word.
- if (skt->getBufferStore(data) == 1 &&
- data.getWord(0) == 0x2a &&
+ if (skt->getBufferStore(data) != 1) {
+ cerr << "rfsv16::getResponse: duff response. "
+ "getBufferStore failed." << endl;
+ } else if (data.getWord(0) == 0x2a &&
data.getWord(2) == data.getLen()-4) {
- data.discardFirstBytes(4);
- long ret = data.getWord(0);
+ long ret = (short)data.getWord(4);
+ data.discardFirstBytes(6);
return ret;
- } else
- status = E_PSI_FILE_DISC;
+ } else {
cerr << "rfsv16::getResponse: duff response. Size field:" <<
-data.getWord(2) << " Frame size:" << data.getLen()-4 << " Result field:" <<
-data.getWord(4) << endl;
+ data.getWord(2) << " Frame size:" <<
+ data.getLen()-4 << " Result field:" <<
+ data.getWord(4) << endl;
+ }
+
+ status = E_PSI_FILE_DISC;
return status;
}
@@ -614,61 +627,88 @@ cerr << "rfsv16::opErr 0x" << hex << setfill('0') << setw(4)
long rfsv16::
fread(long handle, unsigned char *buf, long len)
{
-cerr << "rfsv16::fread ***" << endl;
+ long res;
+ long count = 0;
+
+ while (count < len) {
bufferStore a;
- long remaining = len;
- // Read in blocks of 291 bytes; the maximum payload for an RFSV frame.
- // ( As seen in traces ) - this isn't optimal: RFSV can handle
- // fragmentation of frames, where only the first FREAD RESPONSE frame
- // has a RESPONSE (00 2A), SIZE and RESULT field. Every subsequent frame
+
+ // Read in blocks of 291 bytes; the maximum payload for
+ // an RFSV frame. ( As seen in traces ) - this isn't optimal:
+ // RFSV can handle fragmentation of frames, where only the
+ // first FREAD RESPONSE frame has a RESPONSE (00 2A), SIZE
+ // and RESULT field. Every subsequent frame
// just has data, 297 bytes (or less) of it.
- const int maxblock = 291;
- long readsofar = 0;
- while (remaining) {
- long thisblock = (remaining > maxblock) ? maxblock : remaining;
-cerr << "fread: " << dec << remaining << " bytes remain. This block is " << thisblock
-<< " bytes." << endl;
- a.init();
a.addWord(handle);
- a.addWord(thisblock);
+ a.addWord((len - count) > RFSV16_MAXDATALEN
+ ? RFSV16_MAXDATALEN
+ : (len - count));
sendCommand(FREAD, a);
- long res = getResponse(a);
- remaining -= a.getLen();
-// copy the data to buf
+ res = getResponse(a);
-cerr << "fread getResponse returned " << dec<< (signed short int) res << " data: " << a << dec <<endl;
- if (res) {
+ // The rest of the code treats a 0 return from here
+ // as meaning EOF, so we'll arrange for that to happen.
+ if (res == E_PSI_FILE_EOF)
+ return count;
+ else if (res < 0)
return res;
+
+ res = a.getLen();
+ memcpy(buf, a.getString(), res);
+ count += res;
+ buf += res;
}
- }
- return len;
+ return count;
}
long rfsv16::
fwrite(long handle, unsigned char *buf, long len)
{
-cerr << "rfsv16::fwrite ***" << endl;
- return 0;
+ long res;
+ long count = 0;
+
+ while (count < len) {
+ bufferStore a;
+ int nbytes;
+
+ // Write in blocks of 291 bytes; the maximum payload for
+ // an RFSV frame. ( As seen in traces ) - this isn't optimal:
+ // RFSV can handle fragmentation of frames, where only the
+ // first FREAD RESPONSE frame has a RESPONSE (00 2A), SIZE
+ // and RESULT field. Every subsequent frame
+ // just has data, 297 bytes (or less) of it.
+ nbytes = (len - count) > RFSV16_MAXDATALEN
+ ? RFSV16_MAXDATALEN
+ : (len - count);
+ a.addWord(handle);
+ a.addBytes(buf, nbytes);
+ sendCommand(FWRITE, a);
+ res = getResponse(a);
+ if (res != 0)
+ return res;
+
+ count += nbytes;
+ buf += nbytes;
+ }
+ return count;
}
long rfsv16::
copyFromPsion(const char *from, const char *to, cpCallback_t cb)
{
-cerr << "rfsv16::copyFromPsion" << endl;
long handle;
long res;
long len;
if ((res = fopen(P_FSHARE | P_FSTREAM, from, handle)) != 0)
return res;
-cerr << "fopen response is " << dec << (signed short int)res << endl;
ofstream op(to);
if (!op) {
fclose(handle);
return -1;
}
do {
- unsigned char buf[2000];
+ unsigned char buf[RFSV_SENDLEN];
if ((len = fread(handle, buf, sizeof(buf))) > 0)
op.write(buf, len);
if (cb) {
@@ -681,13 +721,12 @@ cerr << "fopen response is " << dec << (signed short int)res << endl;
fclose(handle);
op.close();
- return len;
+ return len == E_PSI_FILE_EOF ? 0 : len;
}
long rfsv16::
copyToPsion(const char *from, const char *to, cpCallback_t cb)
{
-cerr << "rfsv16::copyToPsion" << endl;
long handle;
long res;
@@ -701,50 +740,30 @@ cerr << "rfsv16::copyToPsion" << endl;
return res;
}
unsigned char *buff = new unsigned char[RFSV_SENDLEN];
- int total = 0;
- while (ip && !ip.eof()) {
+ while (res >= 0 && ip && !ip.eof()) {
ip.read(buff, RFSV_SENDLEN);
- bufferStore tmp(buff, ip.gcount());
- int len = tmp.getLen();
- total += len;
- if (len == 0)
- break;
- bufferStore a;
- a.addDWord(handle);
- a.addBuff(tmp);
- if (!sendCommand(FWRITE, a)) { // FIXME: need to check params
- fclose(handle);
- ip.close();
- delete[]buff;
- return E_PSI_FILE_DISC;
+ res = fwrite(handle, buff, ip.gcount());
+ if (cb)
+ if (!cb(res)) {
+ res = E_PSI_FILE_CANCEL;
}
- res = getResponse(a);
- if (res) {
- fclose(handle);
- ip.close();
- delete[]buff;
- return res;
}
- if (cb) {
- if (!cb(len)) {
- fclose(handle);
- ip.close();
+
delete[]buff;
- return E_PSI_FILE_CANCEL;
- }
- }
- }
fclose(handle);
ip.close();
- delete[]buff;
return 0;
}
long rfsv16::
fsetsize(long handle, long size)
{
-cerr << "rfsv16::fsetsize ***" << endl;
- return 0;
+ bufferStore a;
+ a.addWord(handle);
+ a.addDWord(size);
+ if (!sendCommand(FSETEOF, a))
+ return E_PSI_FILE_DISC;
+ return getResponse(a);
}
/*
@@ -755,8 +774,92 @@ cerr << "rfsv16::fsetsize ***" << endl;
long rfsv16::
fseek(long handle, long pos, long mode)
{
-cerr << "rfsv16::fseek ***" << endl;
- return 0;
+ bufferStore a;
+ long res;
+ long savpos = 0;
+ long realpos;
+ long calcpos = 0;
+
+/*
+ seek-parameter for psion:
+ dword position
+ dword handle
+ dword mode
+ 1 = from start
+ 2 = from current pos
+ 3 = from end
+ ??no more?? 4 = sense recpos
+ ??no more?? 5 = set recpos
+ ??no more?? 6 = text-rewind
+ */
+
+ if ((mode < PSI_SEEK_SET) || (mode > PSI_SEEK_END))
+ return E_PSI_GEN_ARG;
+
+ if ((mode == PSI_SEEK_CUR) && (pos >= 0)) {
+ /* get and save current position */
+ a.init();
+ a.addWord(handle);
+ a.addDWord(0);
+ a.addWord(PSI_SEEK_CUR);
+ if (!sendCommand(FSEEK, a))
+ return E_PSI_FILE_DISC;
+ if ((res = getResponse(a)) != 0)
+ return res;
+ savpos = a.getDWord(0);
+ if (pos == 0)
+ return savpos;
+ }
+ if ((mode == PSI_SEEK_END) && (pos >= 0)) {
+ /* get and save end position */
+ a.init();
+ a.addWord(handle);
+ a.addDWord(0);
+ a.addWord(PSI_SEEK_END);
+ if (!sendCommand(FSEEK, a))
+ return E_PSI_FILE_DISC;
+ if ((res = getResponse(a)) != 0)
+ return res;
+ savpos = a.getDWord(0);
+ if (pos == 0)
+ return savpos;
+ }
+ /* Now the real seek */
+ a.addWord(handle);
+ a.addDWord(pos);
+ a.addWord(mode);
+ if (!sendCommand(FSEEK, a))
+ return E_PSI_FILE_DISC;
+ if ((res = getResponse(a)) != 0)
+ return res;
+ realpos = a.getDWord(0);
+ switch (mode) {
+ case PSI_SEEK_SET:
+ calcpos = pos;
+ break;
+ case PSI_SEEK_CUR:
+ calcpos = savpos + pos;
+ break;
+ case PSI_SEEK_END:
+ return realpos;
+ break;
+ }
+ if (calcpos > realpos) {
+ /* Beyond end of file */
+ res = fsetsize(handle, calcpos);
+ if (res != 0)
+ return res;
+ a.init();
+ a.addWord(handle);
+ a.addDWord(calcpos);
+ a.addWord(PSI_SEEK_SET);
+ if (!sendCommand(FSEEK, a))
+ return E_PSI_FILE_DISC;
+ if ((res = getResponse(a)) != 0)
+ return res;
+ realpos = a.getDWord(0);
+ }
+ return realpos;
}
long rfsv16::
@@ -771,11 +874,11 @@ mkdir(const char* dirName)
// and this needs sending in the length word.
sendCommand(MKDIR, a);
long res = getResponse(a);
- if (!res && a.getLen() == 2) {
+ if (!res) {
// Correct response
- return a.getWord(0);
+ return res;
}
- cerr << "Unknown response from mkdir "<< a <<endl;
+ cerr << "Unknown response from mkdir "<< res <<endl;
return 1;
}
@@ -806,11 +909,11 @@ cerr << "rfsv16::rename ***" << endl;
// and this needs sending in the length word.
sendCommand(RENAME, a);
long res = getResponse(a);
- if (!res && a.getLen() == 2) {
+ if (!res) {
// Correct response
- return a.getWord(0);
+ return res;
}
- cerr << "Unknown response from rename "<< a <<endl;
+ cerr << "Unknown response from rename "<< res <<endl;
return 1;
}
@@ -826,12 +929,85 @@ remove(const char* psionName)
// and this needs sending in the length word.
sendCommand(DELETE, a);
long res = getResponse(a);
- if (!res && a.getLen() == 2) {
+ if (!res) {
// Correct response
- return a.getWord(0);
+ return res;
}
- cerr << "Unknown response from delete "<< a <<endl;
+ cerr << "Unknown response from delete "<< res <<endl;
return 1;
}
+/*
+ * Translate SIBO attributes to standard attributes.
+ */
+long rfsv16::
+attr2std(long attr)
+{
+ long res = 0;
+
+ // Common attributes
+ if (!(attr & P_FAWRITE))
+ res |= PSI_A_RDONLY;
+ if (attr & P_FAHIDDEN)
+ res |= PSI_A_HIDDEN;
+ if (attr & P_FASYSTEM)
+ res |= PSI_A_SYSTEM;
+ if (attr & P_FADIR)
+ res |= PSI_A_DIR;
+ if (attr & P_FAMOD)
+ res |= PSI_A_ARCHIVE;
+ if (attr & P_FAVOLUME)
+ res |= PSI_A_VOLUME;
+
+ // SIBO-specific
+ if (attr & P_FAREAD)
+ res |= PSI_A_READ;
+ if (attr & P_FAEXEC)
+ res |= PSI_A_EXEC;
+ if (attr & P_FASTREAM)
+ res |= PSI_A_STREAM;
+ if (attr & P_FATEXT)
+ res |= PSI_A_TEXT;
+
+ // Do what we can for EPOC
+ res |= PSI_A_NORMAL;
+
+ return res;
+}
+
+/*
+ * Translate standard attributes to SIBO attributes.
+ */
+long rfsv16::
+std2attr(long attr)
+{
+ long res = 0;
+
+ // Common attributes
+ if (!(attr & PSI_A_RDONLY))
+ res |= P_FAWRITE;
+ if (attr & PSI_A_HIDDEN)
+ res |= P_FAHIDDEN;
+ if (attr & PSI_A_SYSTEM)
+ res |= P_FASYSTEM;
+ if (attr & PSI_A_DIR)
+ res |= P_FADIR;
+ if (attr & PSI_A_ARCHIVE)
+ res |= P_FAMOD;
+ if (attr & PSI_A_VOLUME)
+ res |= P_FAVOLUME;
+
+ // SIBO-specific
+ if (attr & PSI_A_READ)
+ res |= P_FAREAD;
+ if (attr & PSI_A_EXEC)
+ res |= P_FAEXEC;
+ if (attr & PSI_A_STREAM)
+ res |= P_FASTREAM;
+ if (attr & PSI_A_TEXT)
+ res |= P_FATEXT;
+
+ return res;
+}
+
diff --git a/lib/rfsv16.h b/lib/rfsv16.h
index 175e540..bb6a947 100644
--- a/lib/rfsv16.h
+++ b/lib/rfsv16.h
@@ -46,6 +46,9 @@ class rfsv16 : public rfsv {
char *opAttr(long);
long opMode(long);
+ long attr2std(long);
+ long std2attr(long);
+
private:
enum commands {
FOPEN = 0, // File Open
diff --git a/lib/rfsv32.cc b/lib/rfsv32.cc
index 69136a3..3980eb9 100644
--- a/lib/rfsv32.cc
+++ b/lib/rfsv32.cc
@@ -203,8 +203,17 @@ micro2time(unsigned long microHi, unsigned long microLo)
micro /= 1000000;
micro -= pes;
micro += EPOCH_DIFF_SECS;
- micro -= EPOCH_2H;
- micro += 3600; /* 1 hour PJC */
+
+ /* Adjust for timezone and daylight saving time */
+ {
+ struct tm *t;
+ long date=micro;
+
+ t = localtime(&date);
+ micro += timezone; /* Adjust for timezone */
+ if (t->tm_isdst) micro -= (60*60); /* Adjust for DST */
+ }
+
return (long) micro;
}
@@ -216,8 +225,17 @@ time2micro(unsigned long time, unsigned long &microHi, unsigned long &microLo)
pes <<= 8;
micro += pes;
micro -= EPOCH_DIFF_SECS;
- micro += EPOCH_2H;
- micro -= 3600; /* 1 hour PJC */
+
+ /* Adjust for timezone and daylight saving time */
+ {
+ struct tm *t;
+ long date=time;
+
+ t = localtime(&date);
+ micro -= timezone; /* Adjust for timezone */
+ if (t->tm_isdst) micro += (60*60); /* Adjust for DST */
+ }
+
micro *= (unsigned long long)1000000;
microLo = (micro & (unsigned long long)0x0FFFFFFFF);
micro >>= 32;
@@ -263,7 +281,7 @@ dir(const char *name, bufferArray * files)
s.addByte(0);
while (d % 4)
d++;
- files->pushBuffer(s);
+ files->append(s);
d += shortLen;
while (d % 4)
d++;
@@ -495,8 +513,12 @@ sendCommand(enum commands cc, bufferStore & data)
serNum = 0;
a.addBuff(data);
result = skt->sendBufferStore(a);
+ if (!result) {
+ reconnect();
+ result = skt->sendBufferStore(a);
if (!result)
status = E_PSI_FILE_DISC;
+ }
return result;
}
@@ -888,3 +910,73 @@ err2psierr(long status)
}
return e2psi[status - E_EPOC_DIR_FULL];
}
+
+
+/*
+ * Translate EPOC attributes to standard attributes.
+ */
+long rfsv32::
+attr2std(long attr)
+{
+ long res = 0;
+
+ // Common attributes
+ if (attr & EPOC_ATTR_RONLY)
+ res |= PSI_A_RDONLY;
+ if (attr & EPOC_ATTR_HIDDEN)
+ res |= PSI_A_HIDDEN;
+ if (attr & EPOC_ATTR_SYSTEM)
+ res |= PSI_A_SYSTEM;
+ if (attr & EPOC_ATTR_DIRECTORY)
+ res |= PSI_A_DIR;
+ if (attr & EPOC_ATTR_ARCHIVE)
+ res |= PSI_A_ARCHIVE;
+ if (attr & EPOC_ATTR_VOLUME)
+ res |= PSI_A_VOLUME;
+
+ // EPOC-specific
+ if (attr & EPOC_ATTR_NORMAL)
+ res |= PSI_A_NORMAL;
+ if (attr & EPOC_ATTR_TEMPORARY)
+ res |= PSI_A_TEMP;
+ if (attr & EPOC_ATTR_COMPRESSED)
+ res |= PSI_A_COMPRESSED;
+
+ // Do what we can for SIBO
+ res |= PSI_A_READ;
+
+ return res;
+}
+
+/*
+ * Translate standard attributes to EPOC attributes.
+ */
+long rfsv32::
+std2attr(long attr)
+{
+ long res = 0;
+
+ // Common attributes
+ if (!(attr & PSI_A_RDONLY))
+ res |= EPOC_ATTR_RONLY;
+ if (attr & PSI_A_HIDDEN)
+ res |= EPOC_ATTR_HIDDEN;
+ if (attr & PSI_A_SYSTEM)
+ res |= EPOC_ATTR_SYSTEM;
+ if (attr & PSI_A_DIR)
+ res |= EPOC_ATTR_DIRECTORY;
+ if (attr & PSI_A_ARCHIVE)
+ res |= EPOC_ATTR_ARCHIVE;
+ if (attr & PSI_A_VOLUME)
+ res |= EPOC_ATTR_VOLUME;
+
+ // EPOC-specific
+ if (attr & PSI_A_NORMAL)
+ res |= EPOC_ATTR_NORMAL;
+ if (attr & PSI_A_TEMP)
+ res |= EPOC_ATTR_TEMPORARY;
+ if (attr & PSI_A_COMPRESSED)
+ res |= EPOC_ATTR_COMPRESSED;
+
+ return res;
+}
diff --git a/lib/rfsv32.h b/lib/rfsv32.h
index 8383e72..2aac5b9 100644
--- a/lib/rfsv32.h
+++ b/lib/rfsv32.h
@@ -44,6 +44,9 @@ class rfsv32 : public rfsv {
char *opAttr(long);
long opMode(long);
+ long attr2std(long);
+ long std2attr(long);
+
private:
enum file_attrib {
diff --git a/lib/rpcs.cc b/lib/rpcs.cc
index 5863c5b..79630cf 100644
--- a/lib/rpcs.cc
+++ b/lib/rpcs.cc
@@ -28,11 +28,21 @@
#include "ppsocket.h"
#include "bufferarray.h"
+static const char * const langstrings[] = {
+ "Test", "English", "French", "German", "Spanish", "Italian", "Swedish",
+ "Danish", "Norwegian", "Finnish", "American", "Swiss French",
+ "Swiss German", "Portugese", "Turkish", "Icelandic", "Russian",
+ "Hungarian", "Dutch", "Belgian Flemish", "Australian",
+ "Belgish French", "Austrian", "New Zealand",
+ "International French", "Czech", "Slovak", "Polish", "Slovenian",
+ 0L
+};
+
//
// public common API
//
void rpcs::
-reconnect()
+reconnect(void)
{
skt->closeSocket();
skt->reconnect();
@@ -40,7 +50,7 @@ reconnect()
}
void rpcs::
-reset()
+reset(void)
{
bufferStore a;
status = E_PSI_FILE_DISC;
@@ -54,13 +64,13 @@ reset()
}
long rpcs::
-getStatus()
+getStatus(void)
{
return status;
}
const char *rpcs::
-getConnectName()
+getConnectName(void)
{
return "SYS$RPCS";
}
@@ -68,16 +78,6 @@ getConnectName()
//
// protected internals
//
-char *rpcs::
-convertSlash(const char *name)
-{
- char *n = strdup(name);
- for (char *p = n; *p; p++)
- if (*p == '/')
- *p = '\\';
- return n;
-}
-
bool rpcs::
sendCommand(enum commands cc, bufferStore & data)
{
@@ -91,16 +91,21 @@ sendCommand(enum commands cc, bufferStore & data)
a.addByte(cc);
a.addBuff(data);
result = skt->sendBufferStore(a);
- if (!result)
- status = E_PSI_FILE_DISC;
+ if (!result) {
+ reconnect();
+ result = skt->sendBufferStore(a);
+ if (!result)
+ status = E_PSI_FILE_DISC;
+ }
return result;
}
-long rpcs::
+int rpcs::
getResponse(bufferStore & data)
{
if (skt->getBufferStore(data) == 1) {
- long ret = data.getByte(0);
+ char ret = data.getByte(0);
+ data.discardFirstBytes(1);
return ret;
} else
status = E_PSI_FILE_DISC;
@@ -113,12 +118,12 @@ getResponse(bufferStore & data)
int rpcs::
getNCPversion(int &major, int &minor)
{
+ int res;
bufferStore a;
+
if (!sendCommand(QUERY_NCP, a))
return E_PSI_FILE_DISC;
- long res = getResponse(a);
- a.discardFirstBytes(1);
- if (res)
+ if ((res = getResponse(a)))
return res;
if (a.getLen() != 2)
return E_PSI_GEN_FAIL;
@@ -131,6 +136,7 @@ int rpcs::
execProgram(const char *program, const char *args)
{
bufferStore a;
+
a.addStringT(program);
int l = strlen(program);
for (int i = 127; i > l; i--)
@@ -139,15 +145,14 @@ execProgram(const char *program, const char *args)
a.addStringT(args);
if (!sendCommand(EXEC_PROG, a))
return E_PSI_FILE_DISC;
- long res = getResponse(a);
-cout << res << " " << a << endl;
- return res;
+ return getResponse(a);
}
int rpcs::
stopProgram(const char *program)
{
bufferStore a;
+
a.addStringT(program);
if (!sendCommand(STOP_PROG, a))
return E_PSI_FILE_DISC;
@@ -158,6 +163,7 @@ int rpcs::
queryProgram(const char *program)
{
bufferStore a;
+
a.addStringT(program);
if (!sendCommand(QUERY_PROG, a))
return E_PSI_FILE_DISC;
@@ -167,13 +173,13 @@ queryProgram(const char *program)
int rpcs::
formatOpen(const char *drive, int &handle, int &count)
{
+ int res;
bufferStore a;
+
a.addStringT(drive);
if (!sendCommand(FORMAT_OPEN, a))
return E_PSI_FILE_DISC;
- long res = getResponse(a);
- a.discardFirstBytes(1);
- if (res)
+ if ((res = getResponse(a)))
return res;
if (a.getLen() != 4)
return E_PSI_GEN_FAIL;
@@ -186,6 +192,7 @@ int rpcs::
formatRead(int handle)
{
bufferStore a;
+
a.addWord(handle);
if (!sendCommand(FORMAT_READ, a))
return E_PSI_FILE_DISC;
@@ -195,13 +202,13 @@ formatRead(int handle)
int rpcs::
getUniqueID(const char *device, long &id)
{
+ int res;
bufferStore a;
+
a.addStringT(device);
if (!sendCommand(GET_UNIQUEID, a))
return E_PSI_FILE_DISC;
- long res = getResponse(a);
- a.discardFirstBytes(1);
- if (res)
+ if ((res = getResponse(a)))
return res;
if (a.getLen() != 4)
return E_PSI_GEN_FAIL;
@@ -210,14 +217,14 @@ getUniqueID(const char *device, long &id)
}
int rpcs::
-getOwnerInfo(bufferArray &ret)
+getOwnerInfo(bufferArray &owner)
{
+ int res;
bufferStore a;
+
if (!sendCommand(GET_OWNERINFO, a))
return E_PSI_FILE_DISC;
- long res = getResponse(a);
- a.discardFirstBytes(1);
- if (res)
+ if ((res = getResponse(a)))
return res;
a.addByte(0);
int l = a.getLen();
@@ -225,13 +232,18 @@ getOwnerInfo(bufferArray &ret)
for (int i = 0; i < l; i++)
if (s[i] == 6)
s[i] = 0;
- ret.clear();
+ owner.clear();
while (l > 0) {
- bufferStore b;
- b.addStringT(s);
- ret += b;
- l -= (strlen(s) + 1);
- s += (strlen(s) + 1);
+ if (*s != '\0') {
+ bufferStore b;
+ b.addStringT(s);
+ owner += b;
+ l -= (strlen(s) + 1);
+ s += (strlen(s) + 1);
+ } else {
+ l--;
+ s++;
+ }
}
return res;
}
@@ -239,12 +251,12 @@ getOwnerInfo(bufferArray &ret)
int rpcs::
getMachineType(int &type)
{
+ int res;
bufferStore a;
+
if (!sendCommand(GET_MACHINETYPE, a))
return E_PSI_FILE_DISC;
- long res = getResponse(a);
- a.discardFirstBytes(1);
- if (res)
+ if ((res = getResponse(a)))
return res;
if (a.getLen() != 2)
return E_PSI_GEN_FAIL;
@@ -253,27 +265,25 @@ getMachineType(int &type)
}
int rpcs::
-fuser(const char *name, char *buf, int bufsize)
+fuser(const char *name, char *buf, int maxlen)
{
+ int res;
bufferStore a;
+ char *p;
+
a.addStringT(name);
if (!sendCommand(FUSER, a))
return E_PSI_FILE_DISC;
- long res = getResponse(a);
- a.discardFirstBytes(1);
- if (res)
+ if ((res = getResponse(a)))
return res;
- int len = ((int)a.getLen() > bufsize) ? bufsize - 1 : a.getLen();
- strncpy(buf, a.getString(0), len);
- buf[len] = '\0';
- char *p;
+ strncpy(buf, a.getString(0), maxlen - 1);
while ((p = strchr(buf, 6)))
- *p = '\n';
+ *p = '\0';
return res;
}
int rpcs::
-quitServer()
+quitServer(void)
{
bufferStore a;
if (!sendCommand(QUIT_SERVER, a))
@@ -281,3 +291,25 @@ quitServer()
return getResponse(a);
}
+const char *rpcs::
+languageString(int code) {
+ for (int i = 0; i <= code; i++)
+ if (langstrings[i] == 0L)
+ return "Unknown";
+ return langstrings[code];
+}
+
+const char *rpcs::
+batteryStatusString(int code) {
+ switch (code) {
+ case PSI_BATT_DEAD:
+ return "Empty";
+ case PSI_BATT_VERYLOW:
+ return "Very low";
+ case PSI_BATT_LOW:
+ return "Low";
+ case PSI_BATT_GOOD:
+ return "Good";
+ }
+ return "Unknown";
+}
diff --git a/lib/rpcs.h b/lib/rpcs.h
index cb71c88..3c569bb 100644
--- a/lib/rpcs.h
+++ b/lib/rpcs.h
@@ -1,37 +1,252 @@
#ifndef _rpcs_h_
#define _rpcs_h_
+#include "psitime.h"
+
class ppsocket;
class bufferStore;
class bufferArray;
+/**
+ * This struct holds the data returned
+ * by @ref rpcs::getMachineInfo.
+ */
+typedef struct machineInfo_t {
+ unsigned long machineType;
+ char machineName[17];
+ unsigned long long machineUID;
+ unsigned long countryCode;
+ char uiLanguage[32];
+
+ unsigned short romMajor;
+ unsigned short romMinor;
+ unsigned short romBuild;
+ unsigned long romSize;
+ bool romProgrammable;
+
+ unsigned long ramSize;
+ unsigned long ramFree;
+ unsigned long ramMaxFree;
+ unsigned long ramDiskSize;
+
+ unsigned long registrySize;
+ unsigned long displayWidth;
+ unsigned long displayHeight;
+
+ psi_timeval time;
+ psi_timezone tz;
+
+ psi_timeval mainBatteryInsertionTime;
+ unsigned long mainBatteryStatus;
+ psi_timeval mainBatteryUsedTime;
+ unsigned long mainBatteryCurrent;
+ unsigned long mainBatteryUsedPower;
+ unsigned long mainBatteryVoltage;
+ unsigned long mainBatteryMaxVoltage;
+
+ unsigned long backupBatteryStatus;
+ unsigned long backupBatteryVoltage;
+ unsigned long backupBatteryMaxVoltage;
+ psi_timeval backupBatteryUsedTime;
+
+ bool externalPower;
+} machineInfo;
+
+/**
+ * Remote procedure call services via PLP
+ *
+ * rpcs provides an interface for communicating
+ * with the Psion's remote procedure call
+ * service. The generic facilities for both,
+ * EPOC and SIBO are implemented here, while
+ * the facilities, unique to each of those
+ * variants are implemented in
+ * @ref rpcs32 or @ref rpcs16 respectively.
+ * These normally are instantiated by using
+ * @ref rpcsfactory.
+ */
class rpcs {
public:
+ /**
+ * Provides a virtual destructor.
+ */
virtual ~rpcs() {};
+
+ /**
+ * Initializes a connection to the remote
+ * machine.
+ */
void reset();
+
+ /**
+ * Attempts to re-establish a remote
+ * connection by first closing the socket,
+ * then connecting again to the ncpd daemon
+ * and finally calling @ref reset.
+ */
void reconnect();
+
+ /**
+ * Retrieves the current status of the
+ * connection.
+ *
+ * @returns The connection status.
+ */
long getStatus();
- // API idendical on SIBO and EPOC
- int getNCPversion(int &, int &);
- int execProgram(const char *, const char *);
+ /**
+ * Retrieves the version of the NCP protocol
+ * on the remote side.
+ *
+ * This function is working with both SIBO and EPOC
+ * devices.
+ *
+ * @param major The major part of the NCP version.
+ * Valid only if returned with no error.
+ * @param minor The minor part of the NCP version.
+ * Valid only if returned with no error.
+ *
+ * @returns A psion error code. 0 = Ok.
+ */
+ int getNCPversion(int &major, int &minor);
+
+ /**
+ * Starts execution of a program on the remote machine.
+ *
+ * This function is working with both SIBO and EPOC
+ * devices.
+ *
+ * @param program The full path of the executable
+ * on the remote machine
+ * @param args The arguments for this program, separated
+ * by space.
+ *
+ * @returns A psion error code. 0 = Ok.
+ */
+ int execProgram(const char *program, const char *args);
+
+ /**
+ * Requests termination of a program running on the
+ * remote machine.
+ *
+ * This function is working with both SIBO and EPOC
+ * devices.
+ *
+ * @param program
+ *
+ * @returns A psion error code. 0 = Ok.
+ */
int stopProgram(const char *);
int queryProgram(const char *);
int formatOpen(const char *, int &, int &);
int formatRead(int);
int getUniqueID(const char *, long &);
+
+ /**
+ * Retrieve owner information of the remote machine.
+ *
+ * This function is working with both SIBO and EPOC
+ * devices.
+ *
+ * @param owner A bufferArray, containing the lines
+ * of the owner info upon return.
+ *
+ * @returns A psion error code. 0 = Ok.
+ */
int getOwnerInfo(bufferArray &);
- int getMachineType(int &);
- int fuser(const char *, char *, int);
+
+ /**
+ * Retrieves the type of machine on the remote side
+ * as defined in @ref #machs.
+ *
+ * This function is working with both SIBO and EPOC
+ * devices
+ *
+ * @param type The code describing the type of machine
+ * on the remote side is stored here on return.
+ *
+ * @returns A psion error code. 0 = Ok.
+ */
+ int getMachineType(int &type);
+
+ /**
+ * Retrieves the name of a process, having a
+ * given file opened on the remote side.
+ *
+ * This function is working with both SIBO and EPOC
+ * devices
+ *
+ * @param name The full path of a file to be checked
+ * for beeing used by a program.
+ * @param buf A buffer which gets filled with the
+ * program's name.
+ * @param maxlen The maximum capacity of the buffer.
+ */
+ int fuser(const char *name, char *buf, int maxlen);
+
+ /**
+ * Requests the remote server to terminate.
+ *
+ * This function is working with both SIBO and EPOC
+ * devices. There is usually no need to call this
+ * function, because the remote server is automatically
+ * stopped on disconnect.
+ *
+ * @returns A psion error code. 0 = Ok.
+ */
int quitServer(void);
+ /**
+ * Maps a language code to a human readable language name.
+ *
+ * @param code The language code to map.
+ *
+ * @returns The name of the language, represented by code, or
+ * "Unknown", if the code does not match one of the known
+ * languages.
+ */
+ const char *languageString(const int code);
+
+ /**
+ * Maps a battery status code to a human readable description.
+ *
+ * @param code The battary status code to map.
+ *
+ * @returns A descriptive text for the battery status, or
+ * "Unknown", if the code does not match a known
+ * battery status.
+ */
+ const char *batteryStatusString(const int code);
+
+
// API different on SIBO and EPOC
virtual int queryDrive(const char, bufferArray &) = 0;
- virtual int getCmdLine(const char *, char *, int) = 0;
+ /**
+ * Retrieves the command line of a running process.
+ *
+ * This function works with EPOC only. Using it with SIBO
+ * machines, returns always an error code E_PSI_NOT_SIBO.
+ *
+ * @param process Name of process. Format: processname.$pid
+ * @param ret The program name and arguments are returned here.
+ *
+ * @return Psion error code. 0 = Ok.
+ */
+ virtual int getCmdLine(const char *process, bufferStore &ret) = 0;
// API only existent on EPOC
// default-methods for SIBO here.
- virtual int getMachineInfo(void) { return E_PSI_NOT_SIBO;}
+ /**
+ * Retrieve general Information about the connected
+ * machine.
+ *
+ * This function works with EPOC only. Using it with SIBO
+ * machines, returns always an error code E_PSI_NOT_SIBO.
+ *
+ * @param machineInfo The struct holding all information on return.
+ * @return Psion error code. 0 = Ok.
+ */
+ virtual int getMachineInfo(machineInfo &) { return E_PSI_NOT_SIBO;}
virtual int closeHandle(int) { return E_PSI_NOT_SIBO;}
virtual int regOpenIter(void) { return E_PSI_NOT_SIBO;}
virtual int regReadIter(void) { return E_PSI_NOT_SIBO;}
@@ -46,13 +261,16 @@ class rpcs {
virtual int queryRead(void) { return E_PSI_NOT_SIBO;}
enum errs {
- E_PSI_GEN_NONE = 0,
+ E_PSI_GEN_NONE = 0,
E_PSI_GEN_FAIL = -1,
- E_PSI_FILE_DISC = -50,
+ E_PSI_FILE_DISC = -50,
// Special error code for "Operation not permitted in RPCS16"
- E_PSI_NOT_SIBO = -200
+ E_PSI_NOT_SIBO = -200
};
+ /**
+ * The known machine types.
+ */
enum machs {
PSI_MACH_UNKNOWN = 0,
PSI_MACH_PC = 1,
@@ -65,15 +283,44 @@ class rpcs {
PSI_MACH_S3C = 8,
PSI_MACH_S5 = 32,
PSI_MACH_WINC = 33,
-//TODO: Code for 5mx
+ // TODO: Code for 5mx
};
- protected:
+ /**
+ * The known interface languages.
+ */
+ enum languagecodes {
+ PSI_LANG_TEST = 0,
+ PSI_LANG_ENGLISH = 1,
+ PSI_LANG_FRENCH = 2,
+ PSI_LANG_GERMAN = 3,
+ };
+
+ /**
+ * The known battery states.
+ */
+ enum batterystates {
+ PSI_BATT_DEAD = 0,
+ PSI_BATT_VERYLOW = 1,
+ PSI_BATT_LOW = 2,
+ PSI_BATT_GOOD = 3,
+ };
- // Vars
+ protected:
+ /**
+ * The socket, used for communication
+ * with ncpd.
+ */
ppsocket *skt;
+
+ /**
+ * The current status of the connection.
+ */
long status;
+ /**
+ * The possible commands.
+ */
enum commands {
QUERY_NCP = 0x00,
EXEC_PROG = 0x01,
@@ -87,17 +334,38 @@ class rpcs {
GET_MACHINETYPE = 0x09,
GET_CMDLINE = 0x0a,
FUSER = 0x0b,
- CONFIG_OPEN = 0x66,
+ GET_MACHINE_INFO = 0x64,
+ REG_OPEN_ITER = 0x66,
+ REG_READ_ITER = 0x67,
+ REG_WRITE = 0x68,
+ REG_READ = 0x69,
+ REG_DELETE = 0x6a,
+ SET_TIME = 0x6b,
+ CONFIG_OPEN = 0x6c,
CONFIG_READ = 0x6d,
+ CONFIG_WRITE = 0x6e,
+ QUERY_OPEN = 0x6f,
+ QUERY_READ = 0x70,
QUIT_SERVER = 0xff
};
- // Communication
- bool sendCommand(enum commands, bufferStore &);
- long getResponse(bufferStore &);
+ /**
+ * Sends a command to the remote side.
+ *
+ * If communication fails, a reconnect is triggered
+ * and a second attempt to transmit the request
+ * is attempted. If that second attempt fails,
+ * the function returns an error an sets rpcs::status
+ * to E_PSI_FILE_DISC.
+ *
+ * @param cc The command to execute on the remote side.
+ * @param data Additional data for this command.
+ *
+ * @returns true on success, false on failure.
+ */
+ bool sendCommand(enum commands cc, bufferStore &data);
+ int getResponse(bufferStore &);
const char *getConnectName();
-
- char *convertSlash(const char *);
};
#endif
diff --git a/lib/rpcs16.cc b/lib/rpcs16.cc
index 2786ee8..a3af320 100644
--- a/lib/rpcs16.cc
+++ b/lib/rpcs16.cc
@@ -57,7 +57,7 @@ cout << dec << "qd: " << res << " " << a.getLen() << " a="<< a << endl;
}
int rpcs16::
-getCmdLine(const char *process, char *buf, int bufsize)
+getCmdLine(const char *process, bufferStore &ret)
{
return 0;
}
diff --git a/lib/rpcs16.h b/lib/rpcs16.h
index 14809ae..c803fff 100644
--- a/lib/rpcs16.h
+++ b/lib/rpcs16.h
@@ -12,7 +12,7 @@ class rpcs16 : public rpcs {
~rpcs16();
int queryDrive(const char, bufferArray &);
- int getCmdLine(const char *, char *, int);
+ int getCmdLine(const char *, bufferStore &);
};
#endif
diff --git a/lib/rpcs32.cc b/lib/rpcs32.cc
index d710b9c..74d5ca4 100644
--- a/lib/rpcs32.cc
+++ b/lib/rpcs32.cc
@@ -48,14 +48,16 @@ int rpcs32::
queryDrive(char drive, bufferArray &ret)
{
bufferStore a;
+ int res;
+
a.addByte(drive);
if (!sendCommand(rpcs::QUERY_DRIVE, a))
return rpcs::E_PSI_FILE_DISC;
- getResponse(a);
+ if ((res = getResponse(a)))
+ return res;
int l = a.getLen();
ret.clear();
-//cout << dec << "qd: " << a.getLen() << " a="<< a << endl;
- while (l > 1) {
+ while (l > 0) {
bufferStore b, c;
const char *s;
char *p;
@@ -66,8 +68,7 @@ queryDrive(char drive, bufferArray &ret)
sl = strlen(s) + 1;
l -= sl;
a.discardFirstBytes(sl);
- p = strstr(s, ".$");
- if (p) {
+ if ((p = strstr(s, ".$"))) {
*p = '\0'; p += 2;
sscanf(p, "%d", &pid);
} else
@@ -82,33 +83,125 @@ queryDrive(char drive, bufferArray &ret)
ret.push(c);
ret.push(b);
}
- return 0;
+ return res;
}
int rpcs32::
-getCmdLine(const char *process, char *buf, int bufsize)
+getCmdLine(const char *process, bufferStore &ret)
{
- return 0;
+ bufferStore a;
+ int res;
+
+ a.addStringT(process);
+ if (!sendCommand(rpcs::GET_CMDLINE, a))
+ return rpcs::E_PSI_FILE_DISC;
+ res = getResponse(a);
+ ret = a;
+ return res;
}
int rpcs32::
+getMachineInfo(machineInfo &mi)
+{
+ bufferStore a;
+ int res;
+
+ if (!sendCommand(rpcs::GET_MACHINE_INFO, a))
+ return rpcs::E_PSI_FILE_DISC;
+ if ((res = getResponse(a)))
+ return res;
+ if (a.getLen() != 256)
+ return E_PSI_GEN_FAIL;
+ mi.machineType = a.getDWord(0);
+ strncpy(mi.machineName, a.getString(16), 16);
+ mi.machineName[16] = '\0';
+ mi.machineUID = a.getDWord(44);
+ mi.machineUID <<= 32;
+ mi.machineUID |= a.getDWord(40);
+ mi.countryCode = a.getDWord(56);
+ strcpy(mi.uiLanguage, languageString(a.getDWord(164)));
+
+ mi.romMajor = a.getByte(4);
+ mi.romMinor = a.getByte(5);
+ mi.romBuild = a.getWord(6);
+ mi.romSize = a.getDWord(140);
+
+ mi.ramSize = a.getDWord(136);
+ mi.ramMaxFree = a.getDWord(144);
+ mi.ramFree = a.getDWord(148);
+ mi.ramDiskSize = a.getDWord(152);
+
+ mi.registrySize = a.getDWord(156);
+ mi.romProgrammable = (a.getDWord(160) != 0);
+
+ mi.displayWidth = a.getDWord(32);
+ mi.displayHeight = a.getDWord(36);
+
+ mi.time.tv_low = a.getDWord(48);
+ mi.time.tv_high = a.getDWord(52);
+
+ mi.tz.utc_offset = a.getDWord(60);
+ mi.tz.dst_zones = a.getDWord(64);
+ mi.tz.home_zone = a.getDWord(68);
+
+ mi.mainBatteryInsertionTime.tv_low = a.getDWord(72);
+ mi.mainBatteryInsertionTime.tv_high = a.getDWord(76);
+ mi.mainBatteryStatus = a.getDWord(80);
+ mi.mainBatteryUsedTime.tv_low = a.getDWord(84);
+ mi.mainBatteryUsedTime.tv_high = a.getDWord(88);
+ mi.mainBatteryCurrent = a.getDWord(92);
+ mi.mainBatteryUsedPower = a.getDWord(96);
+ mi.mainBatteryVoltage = a.getDWord(100);
+ mi.mainBatteryMaxVoltage = a.getDWord(104);
+
+ mi.backupBatteryStatus = a.getDWord(108);
+ mi.backupBatteryVoltage = a.getDWord(112);
+ mi.backupBatteryMaxVoltage = a.getDWord(116);
+ mi.backupBatteryUsedTime.tv_low = a.getDWord(124);
+ mi.backupBatteryUsedTime.tv_high = a.getDWord(128);
+
+ mi.externalPower = (a.getDWord(120) != 0);
+
+ return res;
+}
+
+static unsigned long hhh;
+
+int rpcs32::
configOpen(void)
{
bufferStore a;
-cout << "configOpen:" << endl;
+ int res;
+
if (!sendCommand(rpcs::CONFIG_OPEN, a))
return rpcs::E_PSI_FILE_DISC;
- getResponse(a);
-cout << a << endl;
+ res = getResponse(a);
+cout << "co: r=" << res << " a=" << a << endl;
+ hhh = a.getDWord(0);
+ return 0;
}
int rpcs32::
configRead(void)
{
bufferStore a;
-cout << "configRead:" << endl;
- if (!sendCommand(rpcs::CONFIG_READ, a))
- return rpcs::E_PSI_FILE_DISC;
- getResponse(a);
-cout << a << endl;
+ int res;
+ int l;
+ FILE *f;
+
+ f = fopen("blah", "w");
+ do {
+ a.init();
+ a.addDWord(hhh);
+ if (!sendCommand(rpcs::CONFIG_READ, a))
+ return rpcs::E_PSI_FILE_DISC;
+ if ((res = getResponse(a)))
+ return res;
+ l = a.getLen();
+ cout << "cr: " << l << endl;
+ fwrite(a.getString(0), 1, l, f);
+ } while (l > 0);
+ fclose(f);
+//cout << "cr: r=" << res << " a=" << a << endl;
+ return 0;
}
diff --git a/lib/rpcs32.h b/lib/rpcs32.h
index e33ef10..6c333b4 100644
--- a/lib/rpcs32.h
+++ b/lib/rpcs32.h
@@ -11,9 +11,11 @@ class rpcs32 : public rpcs {
~rpcs32();
int queryDrive(const char, bufferArray &);
- int getCmdLine(const char *, char *, int);
+ int getCmdLine(const char *, bufferStore &);
+ int getMachineInfo(machineInfo &);
+ int configOpen(void);
+ int configRead(void);
#if 0
- int getMachineInfo(void);
int closeHandle(int);
int regOpenIter(void);
int regReadIter(void);
@@ -21,10 +23,8 @@ class rpcs32 : public rpcs {
int regRead(void);
int regDelete(void);
int setTime(void);
-#endif
int configOpen(void);
int configRead(void);
-#if 0
int configWrite(void);
int queryOpen(void);
int queryRead(void);
diff --git a/lib/rpcsfactory.cc b/lib/rpcsfactory.cc
index 7358e56..4fe0bff 100644
--- a/lib/rpcsfactory.cc
+++ b/lib/rpcsfactory.cc
@@ -34,7 +34,7 @@
#include "bufferstore.h"
#include "ppsocket.h"
-rpcsfactory::rpcsfactory(ppsocket *_skt) : serNum(0)
+rpcsfactory::rpcsfactory(ppsocket *_skt) //: serNum(0)
{
skt = _skt;
}
@@ -52,9 +52,10 @@ rpcs * rpcsfactory::create(bool reconnect)
a.addStringT("NCP$INFO");
if (!skt->sendBufferStore(a)) {
if (!reconnect)
- cerr << "rpcsfactory::create couldn't send version request" << endl; else {
+ cerr << "rpcsfactory::create couldn't send version request" << endl;
+ else {
skt->closeSocket();
- serNum = 0;
+ // serNum = 0;
skt->reconnect();
}
return NULL;
@@ -68,7 +69,7 @@ rpcs * rpcsfactory::create(bool reconnect)
}
if ((a.getLen() > 8) && !strncmp(a.getString(), "No Psion", 8)) {
skt->closeSocket();
- serNum = 0;
+ // serNum = 0;
skt->reconnect();
return NULL;
}
diff --git a/lib/rpcsfactory.h b/lib/rpcsfactory.h
index 17a2719..feffaee 100644
--- a/lib/rpcsfactory.h
+++ b/lib/rpcsfactory.h
@@ -5,15 +5,37 @@
class ppsocket;
+/**
+ * A factory for automatically instantiating the correct protocol
+ * variant depending on the connected Psion.
+ */
class rpcsfactory {
public:
+ /**
+ * Constructs a rpcsfactory.
+ *
+ * @param skt The socket to be used for connecting
+ * to the ncpd daemon.
+ */
rpcsfactory(ppsocket * skt);
- virtual rpcs * create(bool);
+
+ /**
+ * Creates a new rpsc instance.
+ *
+ * @param reconnect Set to true, if automatic reconnect
+ * should be performed on failure.
+ *
+ * @returns A pointer to a newly created rpcs instance or
+ * NULL on failure.
+ */
+ virtual rpcs * create(bool reconnect);
private:
- // Vars
+ /**
+ * The socket to be used for connecting to the
+ * ncpd daemon.
+ */
ppsocket *skt;
- int serNum;
};
#endif