diff options
| author | Fritz Elfert <felfert@to.com> | 2000-07-31 03:12:38 +0000 | 
|---|---|---|
| committer | Fritz Elfert <felfert@to.com> | 2000-07-31 03:12:38 +0000 | 
| commit | 7fb94ed43a814788cda019c1e77314abc1626339 (patch) | |
| tree | 50b86a44e2809e6fbcdcd080f2a2dc4dbc37042e | |
| parent | fbb17061d3c622f0786a5d9ad41e8ccd95ef706c (diff) | |
| download | plptools-7fb94ed43a814788cda019c1e77314abc1626339.tar.gz plptools-7fb94ed43a814788cda019c1e77314abc1626339.tar.bz2 plptools-7fb94ed43a814788cda019c1e77314abc1626339.zip | |
Applied mjg-0.6 patch.
Started adding kdoc compliant documentation comments.
Added PsiTime
43 files changed, 2046 insertions, 419 deletions
| @@ -7,3 +7,4 @@ config.status  config.cache  config.log  plptools-*.tar.gz +.vimsession @@ -88,7 +88,9 @@   basic PLP/NCP services for the other two programs. It auto-   connects to the psion, even after unplugging/switching off   therefore it can run always in background (if you have a - spare serial-device) + spare serial-device). If supplied, the -e option will cause ncpd to + automatically exit when the connection to the Psion is lost. This is useful + when used with a patch to mgetty (see the patches directory).   plpftp is a FTP-like program for manipulating files on the Psion. diff --git a/README.0.6-mjg b/README.0.6-mjg new file mode 100644 index 0000000..7e5c737 --- /dev/null +++ b/README.0.6-mjg @@ -0,0 +1,62 @@ +Patches to plptools-0.6, collected by Matt Gumbley +-------------------------------------------------- + +1) Compilation patches to enable builds on Solaris. ftp.cc and ppsocket.cc +2) Christof Meerwald's patches so that ncpd can autoterminate (-e option), and +   patch for mgetty PLP autodetection (in the new patches directory), also a +   patch to make the connection more stable. +3) Peter Cherriman's patch which fixes the "one hour out" bug, which "...is that +   a file timestamp is sometimes different when you do a "ls -l" on a mounted +   psion, than the timestamp listed by the properties box on the psion. + +   My previous fix, no longer worked when the daylight saving changed. Linux  +   stores timestamps internally as the number of seconds since the EPOC in  +   UTC(GMT). However the psion seems stores timestamps as the number of seconds  +   since the EPOC. However the EPOC in defined relative to the currently set  +   timezone on the psion. + +   My new fix takes into account the timezone and DST status provided by the  +   linux system, it now works in by GMT(UTC+0) and BST(UTC+0+DST), but I  +   haven't tested it very much in other timezones, but I think it works.  + +   It provides the correct timestamps apart from files created within a hour  +   of a DST change, however this can't be helped due to the strange way the  +   psion stores timestamps and handles timezone and DST." +4) Added --with-mountdir option to configure to allow the plpnfsd mount point +   to be specified at build time. Default is /mnt/psion. +5) Added /dev/psion at the start of the serial ports probed for. +6) Peter Cherriman's patch that fixes compilation of ftp.cc on some platforms. +7) Jim Hague's patches for SIBO, and later Linux Kernels, from Feb 2000.  +   My apologies to Jim for not merging these sooner.  He says: + +   "I've been doing a little work on getting plptools working with my 3a. ... +    I have plpftp working for file transfer and plpnsfd also working, at least  +    sufficiently to back up my 3a. + +    I have also modified the include files required for the Linux build so  +    that it works with a 2.2 series kernels with the NFSv3 patch applied;  +    actually, all I've done is copy the relevant bits of the old NFSv2 headers. + +    It all seems to work with my 3a, though compared to p3nfsd plpnsfd seems  +    very slow at listing directories - when time permits I shall take a  +    closer look. + +    In addition to my English 3a (v3.22F) I have also tried it on an Italian 3a +    (v3.40F). The latter exhibits some curious behaviour - if you start ncpd,  +    run up plpftp and quit plpftp, the 3a closes its serial port down (drops  +    CTS and DSR) and seems to need a reset before it will re-open the serial  +    port. Again, when time permits I shall see if it does this when using  +    PsiWin." + +    Other parts of Jim's patch: +    "Which reminds me - 0.6 doesn't seem to have working copyFromPsion and +     copyToPsion. I've fixed it up and tidied up the retrieval of Owner  +     Infomation a little - 3as anyway send lots of \0\0\0\0\0, each of which  +     was being displayed in plpftp as a blank line. " + +    Jim's patch removes lots of diagnostics in the rfsv16 code, and looks like +    it fixes lots of stuff I hadn't got round to <hides head in shame>. +    Splendid. + +Last patch update: 18/07/00. + diff --git a/configure.in b/configure.in index 19e8ed4..1d7c53e 100644 --- a/configure.in +++ b/configure.in @@ -61,7 +61,7 @@ AC_ARG_WITH(serial,        AC_MSG_RESULT(Overriding serial line: $DDEV)      ],      [ AC_MSG_CHECKING(for default serial line) -      AC_FIND_CDEV(/dev/tty0p0 /dev/tty00 /dev/ttyS0 /dev/term/a /dev/ttyfa /dev/ttya /dev/tty0 /dev/ttyf1 /dev/cuaa1, DDEV) +      AC_FIND_CDEV(/dev/psion /dev/tty0p0 /dev/tty00 /dev/ttyS0 /dev/term/a /dev/ttyfa /dev/ttya /dev/tty0 /dev/ttyf1 /dev/cuaa1, DDEV)        AC_MSG_RESULT($DDEV)        test "$DDEV" = "NO" && AC_MSG_ERROR(NO serial lines. Use --with-serial.)      ] @@ -108,6 +108,17 @@ AC_ARG_WITH(basedir,  )  AC_SUBST(DBASEDIR) +AC_ARG_WITH(mountdir, +    [  --with-mountdir=DDIR    override default mount point [/mnt/psion]], +    [ DDIR="$withval" +      AC_MSG_RESULT(Overriding mount point: $DDIR) ], +    [ DDIR="/mnt/psion" +      AC_MSG_RESULT(Using default mount point: $DDIR) +    ] +) +AC_SUBST(DDIR) + +  AC_OUTPUT(  	Makefile  	lib/Makefile diff --git a/etc/psion.in b/etc/psion.in index 558828f..8985d40 100755 --- a/etc/psion.in +++ b/etc/psion.in @@ -11,9 +11,17 @@  [ -f @prefix@/sbin/ncpd ] || exit 0  [ -f @prefix@/sbin/plpnfsd ] || exit 0 +MGETTY_HASPLP=false +if grep -qs ^/PLP/ /etc/mgetty+sendfax/login.config ; then +	MGETTY_HASPLP=true +fi +  # See how we were called.  case "$1" in    start) +  	if $MGETTY_HASPLP ; then +		echo "NOT Starting ncpd because mgetty configured for PLP" +	fi  	echo -n "Starting Psion support: "  	daemon @prefix@/sbin/ncpd  	daemon @prefix@/sbin/plpnfsd diff --git a/include/defs.h.in b/include/defs.h.in index ce5f68d..012852e 100644 --- a/include/defs.h.in +++ b/include/defs.h.in @@ -17,10 +17,6 @@  #define DUSER "root" -#ifndef DDIR -# define DDIR "/mnt/psion" -#endif -  #ifndef PSIONHOSTNAME  # define PSIONHOSTNAME "localhost"  #endif @@ -38,6 +34,8 @@  #define DPORT		@DPORT@  #define DDRIVE		"@DDRIVE@"  #define DBASEDIR	"@DBASEDIR@" +#define DDIR		"@DDIR@" +  /* Debugging */ diff --git a/include/linux-misc.h b/include/linux-misc.h new file mode 100644 index 0000000..afe1895 --- /dev/null +++ b/include/linux-misc.h @@ -0,0 +1,52 @@ +/* + * Linux nfs_mount_data version 3 (as expected by mp_mount.c). + * + * We extract it here to avoid some rather nasty fiddling necessary + * to compile with v3 and v4 (the latter as found in the NFS v3 stuff). + */ + +#ifndef	LINUX_MISC_H +#define	LINUX_MISC_H + +/* + * WARNING!  Do not delete or change the order of these fields.  If + * a new field is required then add it to the end.  The version field + * tracks which fields are present.  This will ensure some measure of + * mount-to-kernel version compatibility.  Some of these aren't used yet + * but here they are anyway. + */ +#define NFS_MOUNT_VERSION       3 + +struct nfs_mount_data { +        int             version;                /* 1 */ +        int             fd;                     /* 1 */ +        struct nfs_fh   root;                   /* 1 */ +        int             flags;                  /* 1 */ +        int             rsize;                  /* 1 */ +        int             wsize;                  /* 1 */ +        int             timeo;                  /* 1 */ +        int             retrans;                /* 1 */ +        int             acregmin;               /* 1 */ +        int             acregmax;               /* 1 */ +        int             acdirmin;               /* 1 */ +        int             acdirmax;               /* 1 */ +        struct sockaddr_in addr;                /* 1 */ +        char            hostname[256];          /* 1 */ +        int             namlen;                 /* 2 */ +        unsigned int    bsize;                  /* 3 */ +}; + +/* bits in the flags field */ + +#define NFS_MOUNT_SOFT          0x0001  /* 1 */ +#define NFS_MOUNT_INTR          0x0002  /* 1 */ +#define NFS_MOUNT_SECURE        0x0004  /* 1 */ +#define NFS_MOUNT_POSIX         0x0008  /* 1 */ +#define NFS_MOUNT_NOCTO         0x0010  /* 1 */ +#define NFS_MOUNT_NOAC          0x0020  /* 1 */ +#define NFS_MOUNT_TCP           0x0040  /* 2 */ +#define NFS_MOUNT_VER3          0x0080  /* 3 */ +#define NFS_MOUNT_KERBEROS      0x0100  /* 3 */ +#define NFS_MOUNT_NONLM         0x0200  /* 3 */ +  +#endif diff --git a/include/nfs_prot.h b/include/nfs_prot.h index 16cc31f..8bc490f 100644 --- a/include/nfs_prot.h +++ b/include/nfs_prot.h @@ -9,7 +9,6 @@  #endif  #ifdef linux  # include <sys/time.h> -# include <linux/nfs.h>  #endif  #ifdef __sgi  # include <rpc/types.h> @@ -42,7 +41,7 @@  #define NFSMODE_SOCK 0140000  #define NFSMODE_FIFO 0010000 -#if !defined(hpux) && !defined(linux) && !defined(__sgi) +#if !defined(hpux) && !defined(__sgi)  enum nfsstat {  	NFS_OK = 0,  	NFSERR_PERM = 1, @@ -63,16 +62,12 @@ enum nfsstat {  	NFSERR_STALE = 70,  	NFSERR_WFLUSH = 99  }; -#endif /* !hpux, linux */ +#endif /* !hpux, sgi */ -#ifdef linux -typedef enum nfs_stat nfsstat; -#else  typedef enum nfsstat nfsstat; -#endif  bool_t xdr_nfsstat(); -#if !defined(hpux) && !defined(linux) && !defined(__sgi) +#if !defined(hpux) && !defined(__sgi)  enum ftype {  	NFNON = 0,  	NFREG = 1, @@ -85,7 +80,7 @@ enum ftype {  	NFFIFO = 8  };  typedef enum ftype ftype; -#endif /* !linux, hpux */ +#endif /* !hpux, sgi */  #ifdef __sgi  typedef enum nfsftype ftype; @@ -94,17 +89,12 @@ typedef enum nfsftype ftype;  #ifdef hpux  typedef enum nfsftype ftype;  #endif -#ifdef linux -typedef enum nfs_ftype ftype; -#endif  bool_t xdr_ftype(); -#ifndef linux  struct nfs_fh {  	char data[NFS_FHSIZE];  }; -#endif  typedef struct nfs_fh nfs_fh;  bool_t xdr_nfs_fh(); 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 @@ -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 µHi, unsigned long µLo)  	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"; +} @@ -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 diff --git a/ncpd/link.cc b/ncpd/link.cc index c455324..d07b78b 100644 --- a/ncpd/link.cc +++ b/ncpd/link.cc @@ -90,7 +90,7 @@ send(const bufferStore & buff)  	if (buff.getLen() > 300)  		failed = true;  	else -		sendQueue.pushBuffer(buff); +		sendQueue += buff;  }  bufferArray link:: @@ -116,7 +116,7 @@ poll()  				// Send ack  				if (idLastGot != seq) {  					idLastGot = seq; -					ret.pushBuffer(buff); +					ret += buff;  				} else {  					if (verbose & LNK_DEBUG_LOG)  						cout << "link: DUP\n"; @@ -177,7 +177,7 @@ poll()  		} else {  			if (!sendQueue.empty()) {  				somethingToSend = true; -				toSend = sendQueue.popBuffer(); +				toSend = sendQueue.pop();  				idSent++;  				if (idSent > 7)  					idSent = 0; diff --git a/ncpd/linkchan.cc b/ncpd/linkchan.cc index 4a2a4d4..f8e586f 100644 --- a/ncpd/linkchan.cc +++ b/ncpd/linkchan.cc @@ -60,7 +60,7 @@ ncpDataCallback(bufferStore & a)  				<< srvName << "\"" << endl;  		while (!registerStack.empty()) { -			se = registerStack.popBuffer(); +			se = registerStack.pop();  			if (se.getWord(0) == ser) {  				if (verbose & LINKCHAN_DEBUG_LOG)  					cout << "linkchan: found ser=0x" << hex << setw(4) << @@ -68,7 +68,7 @@ ncpDataCallback(bufferStore & a)  						" on stack -> callBack to waiting chan" << endl;  				ncpDoRegisterAck((int)se.getWord(2));  			} else -				newStack.pushBuffer(se); +				newStack += se;  		}  		registerStack = newStack;  		return; @@ -111,7 +111,7 @@ Register(channel *ch)  	stack.addWord(registerSer);  	stack.addWord(ch->getNcpChannel()); -	registerStack.pushBuffer(stack); +	registerStack += stack;  	a.addByte(0);  	a.addWord(registerSer++);  	a.addString(ch->getNcpConnectName()); diff --git a/ncpd/main.cc b/ncpd/main.cc index 3a0ddb6..2c0fd3d 100644 --- a/ncpd/main.cc +++ b/ncpd/main.cc @@ -79,7 +79,7 @@ pollSocketConnections(int &numScp, socketChan ** scp)  void  usage()  { -	cerr << "Usage : ncpd [-V] [-v logclass] [-d] [-p <port>] [-s <device>] [-b <baudrate>]\n"; +	cerr << "Usage : ncpd [-V] [-v logclass] [-d] [-e] [-p <port>] [-s <device>] [-b <baudrate>]\n";  	exit(1);  } @@ -90,6 +90,7 @@ main(int argc, char **argv)  	IOWatch iow;  	int pid;  	bool dofork = true; +	bool autoexit = false;  	// Command line parameter processing  	int sockNum = DPORT; @@ -120,7 +121,7 @@ main(int argc, char **argv)  			if (!strcmp(argv[i], "pd"))  				pverbose |= PKT_DEBUG_DUMP;  			if (!strcmp(argv[i], "ph")) -				lverbose |= PKT_DEBUG_HANDSHAKE; +				pverbose |= PKT_DEBUG_HANDSHAKE;  			if (!strcmp(argv[i], "m"))  				verbose = true;  			if (!strcmp(argv[i], "all")) { @@ -133,6 +134,8 @@ main(int argc, char **argv)  			baudRate = atoi(argv[++i]);  		} else if (!strcmp(argv[i], "-d")) {  			dofork = 0; +		} else if (!strcmp(argv[i], "-e")) { +			autoexit = true;  		} else if (!strcmp(argv[i], "-V")) {  			cout << "ncpd version " << VERSION << endl;  			exit(0); @@ -180,6 +183,9 @@ main(int argc, char **argv)  						iow.watch(1, 0);  					if (a->hasFailed()) { +						if (autoexit) +							break; +  						iow.watch(5, 0);  						if (verbose)  							cout << "ncp: restarting\n"; diff --git a/ncpd/mp_serial.c b/ncpd/mp_serial.c index b153e77..05a014c 100644 --- a/ncpd/mp_serial.c +++ b/ncpd/mp_serial.c @@ -153,7 +153,7 @@ init_serial(const char *dev, int speed, int debug)  #endif  #if defined(sun) || defined(linux) || defined(__sgi) || defined(__NetBSD__)  	ti.c_cflag = CS8 | HUPCL | clocal | CRTSCTS | CREAD; -	ti.c_iflag = IGNBRK | IGNPAR; +	ti.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF;  	ti.c_cc[VMIN] = 1;  	ti.c_cc[VTIME] = 0;  #endif diff --git a/ncpd/ncp.cc b/ncpd/ncp.cc index e1bf96a..1a5c317 100644 --- a/ncpd/ncp.cc +++ b/ncpd/ncp.cc @@ -113,7 +113,7 @@ poll()  	bufferArray res(l->poll());  	if (!res.empty()) {  		do { -			bufferStore s = res.popBuffer(); +			bufferStore s = res.pop();  			if (s.getLen() > 1) {  				int channel = s.getByte(0);  				s.discardFirstBytes(1); diff --git a/ncpd/packet.cc b/ncpd/packet.cc index 26823c8..53774d6 100644 --- a/ncpd/packet.cc +++ b/ncpd/packet.cc @@ -54,6 +54,7 @@ iow(_iow)  	inPtr = inBuffer = new unsigned char[BUFFERLEN + 1];  	outPtr = outBuffer = new unsigned char[BUFFERLEN + 1];  	inLen = outLen = termLen = 0; +	foundSync = 0;  	esc = false;  	crcIn = crcOut = 0; @@ -87,7 +88,7 @@ void packet::  send(unsigned char type, const bufferStore & b)  {  	if (verbose & PKT_DEBUG_LOG) { -		cout << "packet: >> "; +		cout << "packet: type " << hex << (int) type << " >> ";  		if (verbose & PKT_DEBUG_DUMP)  			cout << b << endl;  		else @@ -185,7 +186,7 @@ get(unsigned char &type, bufferStore & ret)  	if (verbose & PKT_DEBUG_LOG) {  		cout << "packet: get ";  		if (verbose & PKT_DEBUG_DUMP) { -			for (int i = 0; i < termLen; i++) +			for (int i = foundSync - 3; i < termLen; i++)  				cout << hex << setw(2) << setfill('0') << (int) inBuffer[i] << " ";  		} else  			cout << "len=" << dec << termLen; @@ -193,6 +194,7 @@ get(unsigned char &type, bufferStore & ret)  	}  	inLen -= termLen;  	termLen = 0; +	foundSync = 0;  	bool crcOk = (endPtr[0] == ((crcIn >> 8) & 0xff) && endPtr[1] == (crcIn & 0xff));  	if (inLen > 0)  		memmove(inBuffer, &endPtr[2], inLen); @@ -218,15 +220,29 @@ terminated()  	if (inLen < 6)  		return false;  	p = inBuffer + termLen; -	if (termLen == 0) { +	if (!foundSync) { +	  while (!foundSync && (inLen - termLen >= 6)) +	  { +		termLen++;  		if (*p++ != 0x16) -			return false; +			continue; +		termLen++;  		if (*p++ != 0x10) -			return false; +			continue; +		termLen++;  		if (*p++ != 0x02) +			continue; +		foundSync = termLen; +	  } +	  if (!foundSync)  			return false; + +	if (verbose & PKT_DEBUG_LOG) { +	  if (foundSync != 3) +	    cout << "packet: terminated found sync at " << foundSync << endl; +	}  		esc = false; -		termLen = 3; +		// termLen = 3;  		crcIn = 0;  		rcv.init();  	} diff --git a/ncpd/packet.h b/ncpd/packet.h index 26d4282..5c4bb4f 100644 --- a/ncpd/packet.h +++ b/ncpd/packet.h @@ -63,6 +63,7 @@ class packet {  		int inLen;  		int outLen;  		int termLen; +		int foundSync;  		int fd;  		short int verbose;  		bool esc; diff --git a/patches/README b/patches/README new file mode 100644 index 0000000..11b7c95 --- /dev/null +++ b/patches/README @@ -0,0 +1,16 @@ +The following patches may be applied to other programs to allow them to operate +better with plptools. + +mgetty-1.1.21-plp.diff is from Christof Meerwald, and adds autodetection  +support for the PLP-protocol to mgetty - thus mgetty can autodetect a +Psion connected to the serial port and execute ncpd (with the autoexit +option). Having mgetty watch the serial port makes it a lot more easy to +switch between a PLP (file transfer) and a PPP (TCP/IP) connection. Christof +used the following login.conf for mgetty: + +/AutoPPP/ -     -       /usr/sbin/pppd +/PLP/   -       -       /usr/sbin/ncpd -d -e +*       -       -       /bin/login @ + + +-- MJG diff --git a/patches/mgetty-1.1.21-plp.diff b/patches/mgetty-1.1.21-plp.diff new file mode 100644 index 0000000..943a173 --- /dev/null +++ b/patches/mgetty-1.1.21-plp.diff @@ -0,0 +1,40 @@ +diff -ur mgetty-1.1.21/logname.c mgetty-1.1.21.new/logname.c +--- mgetty-1.1.21/logname.c	Tue Sep  1 11:56:19 1998 ++++ mgetty-1.1.21.new/logname.c	Sat Jan  1 17:12:11 2000 +@@ -270,6 +270,9 @@ +     static int ppp_level = 0, ppp_escaped = 0; +     char   ppp_ch; + #endif ++#if 1 ++    static int plp_level = 0; ++#endif +      +     /* read character by character! */ +     tio_save = *tio; +@@ -413,6 +416,26 @@ +             ppp_level = 0; + 	    ppp_escaped = 0; +         } ++#endif ++#if 1 ++	if (ch == '\026') ++	{ ++	  plp_level = 1; ++	} ++	else if ((ch == '\020') && (plp_level == 1)) ++	{ ++	  plp_level = 2; ++	} ++	else if ((ch == '\002') && (plp_level == 2)) ++	{ ++	  strcpy (buf, "/PLP/"); ++	  i=5; ++	  ch = '\r'; ++	} ++	else ++	{ ++	  plp_level = 0; ++	} + #endif +          + #ifdef JANUS diff --git a/plpftp/ftp.cc b/plpftp/ftp.cc index 45ec2eb..b46e24a 100644 --- a/plpftp/ftp.cc +++ b/plpftp/ftp.cc @@ -25,9 +25,11 @@  #include <sys/types.h>  #include <dirent.h>  #include <stream.h> +#include <fstream.h>  #include <string.h>  #include <ctype.h>  #include <stdlib.h> +#include <stdio.h>  #include <iomanip.h>  #include <unistd.h>  #include <sys/time.h> @@ -43,7 +45,6 @@  #if HAVE_LIBREADLINE  extern "C"  { -#include <stdio.h>  #include <readline/readline.h>  #if HAVE_LIBHISTORY  #include <readline/history.h> @@ -53,7 +54,6 @@ extern "C"  {  static char psionDir[1024];  static rfsv *comp_a; -static rpcs *comp_r;  static int continueRunning; @@ -184,6 +184,8 @@ sigint_handler2(int i) {  	signal(SIGINT, sigint_handler2);  } +const char *datefmt = "%c"; +  int ftp::  session(rfsv & a, rpcs & r, int xargc, char **xargv)  { @@ -205,7 +207,7 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv)  	}  	if (!once) {  		bufferArray b; -		if (!r.getOwnerInfo(b)) { +		if (!(res = r.getOwnerInfo(b))) {  			int machType;  			r.getMachineType(machType);  			cout << "Connected to "; @@ -251,7 +253,8 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv)  			while (!b.empty())  				cout << "  " << b.pop().getString() << endl;  			cout << endl; -		} +		} else +			cerr << "OwnerInfo returned error " << res << endl;  	}  	if (!strcmp(DDRIVE, "AUTO")) { @@ -334,9 +337,7 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv)  			else {  				// never used to do this  				char dateBuff[100]; -                               	struct tm *t; -                               	t = localtime(&time); -                               	strftime(dateBuff, 100, "%c", t); +                               	strftime(dateBuff, sizeof(dateBuff), datefmt, localtime(&time));                                 	cout << a.opAttr(attr);                                 	cout << " " << dec << setw(10) << setfill(' ') << size;                                 	cout << " " << dateBuff; @@ -364,9 +365,7 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv)  				errprint(res, a);  			else {  				char dateBuff[100]; -				struct tm *t; -				t = localtime(&mtime); -				strftime(dateBuff, 100, "%c %Z", t); +                               	strftime(dateBuff, sizeof(dateBuff), datefmt, localtime(&mtime));  				cout << dateBuff << endl;  			}  			continue; @@ -456,9 +455,7 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv)  					long size = s.getDWord(4);  					long attr = s.getDWord(8);  					char dateBuff[100]; -                                	struct tm *t; -                                	t = localtime(&date); -                                	strftime(dateBuff, 100, "%c", t); +                                	strftime(dateBuff, sizeof(dateBuff), datefmt, localtime(&date));                                  	cout << a.opAttr(attr);                                  	cout << " " << dec << setw(10) << setfill(' ') << size;                                  	cout << " " << dateBuff; @@ -748,10 +745,14 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv)  			continue;  		}  		// RPCS commands -		// if (!strcmp(argv[0], "xxx")) { -		// 	r.configOpen(); -		// 	continue; -		// } +		if (!strcmp(argv[0], "x")) { +			r.configOpen(); +			continue; +		} +		if (!strcmp(argv[0], "y")) { +			r.configRead(); +			continue; +		}  		if (!strcmp(argv[0], "run") && (argc >= 2)) {  			char argbuf[1024];  			char cmdbuf[1024]; @@ -772,6 +773,99 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv)  			r.execProgram(cmdbuf, argbuf);  			continue;  		} +		if (!strcmp(argv[0], "machinfo")) { +			machineInfo mi; +			if ((res = r.getMachineInfo(mi))) { +				errprint(res, a); +				continue; +			} + +			cout << "General:" << endl; +			cout << "  Machine Type: " << mi.machineType << endl; +			cout << "  Machine Name: " << mi.machineName << endl; +			cout << "  Machine UID:  " << hex << mi.machineUID << dec << endl; +			cout << "  UI Language:  " << mi.uiLanguage << endl; +			cout << "ROM:" << endl; +			cout << "  Version:      " << mi.romMajor << "." << setw(2) << setfill('0') << +				mi.romMinor << "(" << mi.romBuild << ")" << endl; +			cout << "  Size:         " << mi.romSize / 1024 << "k" << endl; +			cout << "  Programmable: " << +				(mi.romProgrammable ? "yes" : "no") << endl; +			cout << "RAM:" << endl; +			cout << "  Size:         " << mi.ramSize / 1024 << "k" << endl; +			cout << "  Free:         " << mi.ramFree / 1024 << "k" << endl; +			cout << "  Free max:     " << mi.ramMaxFree / 1024 << "k" << endl; +			cout << "RAM disk size:  " << mi.ramDiskSize / 1024 << "k" << endl; +			cout << "Registry size:  " << mi.registrySize << endl; +			cout << "Display size:   " << mi.displayWidth << "x" << +				mi.displayHeight << endl; +			cout << "Time:" << endl; +			PsiTime pt(&mi.time, &mi.tz); +			cout << "  Current time: " << pt << endl; +			cout << "  UTC offset:   " << mi.tz.utc_offset << " seconds" << endl; +			cout << "  DST:          " << +				(mi.tz.dst_zones & PsiTime::PSI_TZ_HOME ? "yes" : "no") << endl; +			cout << "  Timezone:     " << mi.tz.home_zone << endl; +			cout << "  Country Code: " << mi.countryCode << endl; +			cout << "Main battery:" << endl; +			pt.setPsiTime(&mi.mainBatteryInsertionTime); +			cout << "  Changed at:   " << pt << endl; +			cout << "  Used for:     " << mi.mainBatteryUsedTime << endl; +			cout << "  Status:       " << +				r.batteryStatusString(mi.mainBatteryStatus) << endl; +			cout << "  Current:      " << mi.mainBatteryCurrent << " mA" << endl; +			cout << "  UsedPower:    " << mi.mainBatteryUsedPower << " mAs" << endl; +			cout << "  Voltage:      " << mi.mainBatteryVoltage << " mV" << endl; +			cout << "  Max. voltage: " << mi.mainBatteryMaxVoltage << " mV" << endl; +			cout << "Backup battery:" << endl; +			cout << "  Status:       " << +				r.batteryStatusString(mi.backupBatteryStatus) << endl; +			cout << "  Voltage:      " << mi.backupBatteryVoltage << " mV" << endl; +			cout << "  Max. voltage: " << mi.backupBatteryMaxVoltage << " mV" << endl; +			cout << "  Used for:     " << mi.backupBatteryUsedTime << endl; +			continue; +		} +		if (!strcmp(argv[0], "runrestore") && (argc == 2)) { +			ifstream ip(argv[1]); +			if (!ip) { +				cerr << "Could not read processlist " << argv[1] << endl; +				continue; +			} +			while (!ip.eof()) { +				char cmd[256]; +				char arg[256]; +				ip >> cmd >> arg; +				if ((res = r.execProgram(cmd, arg))) { +					cerr << "Could not start " << cmd << " " << arg << endl; +					errprint(res, a); +				} +			} +			ip.close(); +			continue; +		} +		if (!strcmp(argv[0], "killsave") && (argc == 2)) { +			bufferArray tmp; +			ofstream op(argv[1]); +			if (!op) { +				cerr << "Could not write processlist " << argv[1] << endl; +				continue; +			} +			r.queryDrive('C', tmp); +			while (!tmp.empty()) { +				char pbuf[128]; +				bufferStore cmdargs; +				bufferStore bs = tmp.pop(); +				int pid = bs.getWord(0); +				const char *proc = bs.getString(2); +				sprintf(pbuf, "%s.$%d", proc, pid); +				bs = tmp.pop(); +				if (r.getCmdLine(pbuf, cmdargs) == 0) +					op << cmdargs.getString(0) << " " << bs.getString(0) << endl; +				r.stopProgram(pbuf); +			} +			op.close(); +			continue; +		}  		if (!strcmp(argv[0], "kill") && (argc >= 2)) {  			bufferArray tmp, tmp2;  			bool anykilled = false; @@ -834,7 +928,8 @@ errprint(long errcode, rfsv & a) {  static char *all_commands[] = {  	"pwd", "ren", "touch", "gtime", "test", "gattr", "sattr", "devs",  	"dir", "ls", "dircnt", "cd", "lcd", "get", "put", "mget", "mput", -	"del", "rm", "mkdir", "rmdir", "prompt", "bye", "ps", "kill", "run", NULL +	"del", "rm", "mkdir", "rmdir", "prompt", "bye", +	"ps", "kill", "killsave", "runrestore", "run", "machinfo", NULL  };  static char *localfile_commands[] = { diff --git a/plpnfsd/main.cc b/plpnfsd/main.cc index e322685..6bf0f01 100644 --- a/plpnfsd/main.cc +++ b/plpnfsd/main.cc @@ -46,14 +46,14 @@ long rfsv_dir(const char *file, dentry **e) {  	ret = a->dir(&(*file), &entries);  	while (!entries.empty()) {  		bufferStore s; -		s = entries.popBuffer(); +		s = entries.pop();  		tmp = *e;  		*e = (dentry *)malloc(sizeof(dentry));  		if (!*e)  			return -1;  		(*e)->time = s.getDWord(0);  		(*e)->size = s.getDWord(4); -		(*e)->attr = s.getDWord(8); +		(*e)->attr = a->attr2std(s.getDWord(8));  		(*e)->name = strdup(s.getString(12));  		(*e)->next = tmp;  	} @@ -138,7 +138,6 @@ static long rfsv_opencached(const char *name, long mode) {  }  long rfsv_read(char *buf, long offset, long len, char *name) { -	// FIXME: this might break on RFSV16?  	long ret = 0;  	if (!a) @@ -161,7 +160,6 @@ long rfsv_read(char *buf, long offset, long len, char *name) {  }  long rfsv_write(char *buf, long offset, long len, char *name) { -	// FIXME: this might break on RFSV16?  	long ret = 0;  	if (!a) @@ -196,7 +194,6 @@ long rfsv_setmtime(const char *name, long time) {  long rfsv_setsize(const char *name, long size) {  	long ph;  	long ret; -	// FIXME: this might break on RFSV16?  	if (!a)  		return -1; @@ -215,14 +212,19 @@ long rfsv_setattr(const char *name, long sattr, long dattr) {  		return -1;  	if (a_filename && !strcmp(name, a_filename))  		rfsv_closecached(); -	long ret = a->fsetattr(name, dattr, sattr); -	return ret; +	dattr = a->std2attr(dattr); +	sattr = a->std2attr(sattr); +	return a->fsetattr(name, dattr, sattr);  }  long rfsv_getattr(const char *name, long *attr, long *size, long *time) { +	long res, psiattr; +	  	if (!a)  		return -1; -	return a->fgeteattr(&(*name), &(*attr), &(*size), &(*time)); +	res = a->fgeteattr(&(*name), &psiattr, &(*size), &(*time)); +	*attr = a->attr2std(psiattr); +	return res;  }  long rfsv_statdev(char letter) { diff --git a/plpnfsd/mp_mount.c b/plpnfsd/mp_mount.c index f0a82d4..0f9e1e9 100644 --- a/plpnfsd/mp_mount.c +++ b/plpnfsd/mp_mount.c @@ -66,7 +66,7 @@ static char nfshost[128];  #ifndef __GLIBC__  #include <linux/fs.h>		/* struct nfs_mount_data */  #endif -#include <linux/nfs_mount.h>	/* struct nfs_mount_data */ +#include "linux-misc.h"		/* struct nfs_mount_data */  #include <arpa/inet.h>		/* inet_addr() */  #endif  #ifdef _IBMR2 @@ -75,7 +75,6 @@ static char nfshost[128];  #include <sys/vmount.h>  #endif -  #ifndef DONT_UPDATE_MTAB  #if defined(sun) && defined(__SVR4)  #include <sys/mnttab.h> diff --git a/plpnfsd/mp_pfs_ops.c b/plpnfsd/mp_pfs_ops.c index 669d435..71ed2e9 100644 --- a/plpnfsd/mp_pfs_ops.c +++ b/plpnfsd/mp_pfs_ops.c @@ -106,29 +106,35 @@ attr2pattr(long oattr, long nattr, long *psisattr, long *psidattr)  	 * work properly  	 */  	*psisattr = *psidattr = 0; +	if ((oattr & 0400) != (nattr & 0400)) { +		if (nattr & 0400)		/* readable */ +			*psidattr |= PSI_A_READ; +		else +			*psisattr |= PSI_A_READ; +	}  	if ((oattr & 0200) != (nattr & 0200)) {  		if (nattr & 0200)		/* readonly */ -			*psidattr |= 0x01; +			*psidattr |= PSI_A_RDONLY;  		else -			*psisattr |= 0x01; +			*psisattr |= PSI_A_RDONLY;  	}  	if ((oattr & 0020) != (nattr & 0020)) {  		if (nattr & 0020)	/* group-write    -> archive */ -			*psisattr |= 0x20; +			*psisattr |= PSI_A_ARCHIVE;  		else -			*psidattr |= 0x20; +			*psidattr |= PSI_A_ARCHIVE;  	}  	if ((oattr & 0004) != (nattr & 0004)) {  		if (nattr & 0004)		/* Not world-read -> hidden  */ -			*psidattr |= 0x02; +			*psidattr |= PSI_A_HIDDEN;  		else -			*psisattr |= 0x02; +			*psisattr |= PSI_A_HIDDEN;  	}  	if ((oattr & 0002) != (nattr & 0002)) {  		if (nattr & 0002)		/* world-write    -> system */ -			*psisattr |= 0x04; +			*psisattr |= PSI_A_SYSTEM;  		else -			*psidattr |= 0x04; +			*psidattr |= PSI_A_SYSTEM;  	}  } @@ -137,7 +143,7 @@ dpattr2attr(long psiattr, long size, long ftime, fattr *fp, int inode)  {  	bzero((char *) fp, sizeof(*fp)); -	if (psiattr & 0x10) { +	if (psiattr & PSI_A_DIR) {  		fp->type = NFDIR;  		fp->mode = NFSMODE_DIR | 0700;  		/* @@ -159,17 +165,18 @@ dpattr2attr(long psiattr, long size, long ftime, fattr *fp, int inode)  		 * Following flags have to be set in order to let backups  		 * work properly  		 */ +		if (psiattr & PSI_A_READ)  		fp->mode |= 0400;		/* File readable (?) */ -		if (!(psiattr & 0x01)) +		if (!(psiattr & PSI_A_RDONLY))  			fp->mode |= 0200;	/* File writeable  */  		/* fp->mode |= 0100;		   File executable */ -		if (!(psiattr & 0x02)) +		if (!(psiattr & PSI_A_HIDDEN))  			fp->mode |= 0004;	/* Not Hidden  <-> world read */ -		if (psiattr & 0x04) +		if (psiattr & PSI_A_SYSTEM)  			fp->mode |= 0002;	/* System      <-> world write */ -		if (psiattr & 0x40) +		if (psiattr & PSI_A_VOLUME)  			fp->mode |= 0001;	/* Volume      <-> world exec */ -		if (psiattr & 0x20) +		if (psiattr & PSI_A_ARCHIVE)  			fp->mode |= 0020;	/* Modified    <-> group write */  	/*		fp->mode |= 0040;	 Byte        <-> group read */  	/*		fp->mode |= 0010;	 Text        <-> group exec */ @@ -189,7 +196,7 @@ pattr2attr(long psiattr, long size, long ftime, fattr *fp, unsigned char *fh)  {  	bzero((char *) fp, sizeof(*fp)); -	if (psiattr & 0x10) { +	if (psiattr & PSI_A_DIR) {  		fp->type = NFDIR;  		fp->mode = NFSMODE_DIR | 0700;  		/* @@ -211,17 +218,18 @@ pattr2attr(long psiattr, long size, long ftime, fattr *fp, unsigned char *fh)  		 * Following flags have to be set in order to let backups  		 * work properly  		 */ +		if (psiattr & PSI_A_READ)  		fp->mode |= 0400;		/* File readable (?) */ -		if (!(psiattr & 0x01)) +		if (!(psiattr & PSI_A_RDONLY))  			fp->mode |= 0200;	/* File writeable  */  		/* fp->mode |= 0100;		   File executable */ -		if (!(psiattr & 0x02)) +		if (!(psiattr & PSI_A_HIDDEN))  			fp->mode |= 0004;	/* Not Hidden  <-> world read */ -		if (psiattr & 0x04) +		if (psiattr & PSI_A_SYSTEM)  			fp->mode |= 0002;	/* System      <-> world write */ -		if (psiattr & 0x40) +		if (psiattr & PSI_A_VOLUME)  			fp->mode |= 0001;	/* Volume      <-> world exec */ -		if (psiattr & 0x20) +		if (psiattr & PSI_A_ARCHIVE)  			fp->mode |= 0020;	/* Modified    <-> group write */  	/*		fp->mode |= 0040;	 Byte        <-> group read */  	/*		fp->mode |= 0010;	 Text        <-> group exec */ diff --git a/plpnfsd/rfsv_api.h b/plpnfsd/rfsv_api.h index d4a996b..14c26d5 100644 --- a/plpnfsd/rfsv_api.h +++ b/plpnfsd/rfsv_api.h @@ -29,4 +29,19 @@ extern long rfsv_statdev(char letter);  extern long rfsv_isalive();  extern long rfsv_closecached(void); +/* File attributes, C-style */ +#define	PSI_A_RDONLY		0x0001 +#define	PSI_A_HIDDEN		0x0002 +#define	PSI_A_SYSTEM		0x0004 +#define PSI_A_DIR		0x0008 +#define PSI_A_ARCHIVE		0x0010 +#define PSI_A_VOLUME		0x0020 +#define PSI_A_NORMAL		0x0040 +#define PSI_A_TEMP		0x0080 +#define PSI_A_COMPRESSED	0x0100 +#define PSI_A_READ		0x0200 +#define PSI_A_EXEC		0x0400 +#define PSI_A_STREAM		0x0800 +#define PSI_A_TEXT		0x1000 +  #endif | 
