diff options
53 files changed, 3722 insertions, 545 deletions
@@ -3,7 +3,6 @@ Makefile aclocal.m4 configure libtool -stamp-h.in config.status config.cache config.log @@ -0,0 +1,13 @@ +Changes from Version 0.4 to 0.5: + + - merged all stuff from Matt Gumbley's plptools-0.4-mjg5 + see his README.mjg + - Added a speedup-patch for plpnfsd from Rudol Koenig. This + should also solve Olaf Flebbe's problems as a side effect. + - Added command- and filename-completion to plpftp + - Changed plpftp's default-drive to "AUTO". This triggers + auto-detection of available drives and selecting the first one. + - fixed various bugs in plpftp + - added hash printing in plpftp. + - Added new commands "ps", "kill" and "run" to plpftp (these should + work at least for Series5. For Series3: INCOMPLETE) @@ -2,7 +2,7 @@ Basic Installation ================== These are generic installation instructions. - For package-specific stuff, look into README. + >>>> For package-specific stuff, look into README. <<<< The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses diff --git a/Makefile.am b/Makefile.am index 94ecd0f..fc7f1fc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # $Id$ # SUBDIRS = lib ncpd plpnfsd plpftp -EXTRA_DIST = COPYING README TODO INSTALL include/*.h* etc/*magic etc/*.in +EXTRA_DIST = COPYING README TODO INSTALL README.mjg include/*.h* etc/*magic etc/*.in DISTCLEANFILES = etc/psion AUTOMAKE_OPTIONS = foreign diff --git a/Makefile.cvs b/Makefile.cvs index b7e3170..72d73e0 100644 --- a/Makefile.cvs +++ b/Makefile.cvs @@ -6,14 +6,14 @@ devel: autoheader automake autoconf - touch stamp-h.in + touch include/stamp-h.in dist: aclocal autoheader automake --include-deps autoconf - touch stamp-h.in + touch include/stamp-h.in ./configure $(MAKE) dist @@ -4,8 +4,7 @@ - p3nfsd-5.4 by Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) an nfs daemon for Psion series 3 and 5 - - plp_1_7 by Philip Proudman - (former email, current address unknown proudman@btinternet.com) + - plp_1_7 by Philip Proudman (phil@proudman51.freeserve.co.uk) I want to thank both authors for their nice packages and for making these available under GPL which makes it possible for me to @@ -25,6 +24,14 @@ because a) i can't test it and b) Sibo support is dropped by Psion. + Since version 0.5, there is also starting support for RPC-service + on the Psion. Note the new commands "ps", "kill" and "run" in + plpftp. This support was only possible because of Alexander Thoukydides' + excellent documentation at + http://www.btinternet.com/~thouky/software/psifs/plp.html + Thanks a lot for that. Also Psion-3 support is now added by Matt Gumbley + (matt@gumbley.demon.co.uk) + How to install: ./configure @@ -54,6 +61,20 @@ overrides the default port number, where ncpd listens and plpftp resp. plpnfsd connects to. + --with-drive=drivespec + + overrides the default drive for plpftp. The default "AUTO" + triggers a drive-scan on the psion and sets the drive to + the first drive found. If you don't want that, specify + C: for example. + + --with-basedir=dirspec + + overrides the default directory for plpftp. The default is \\ + which means the root-dir. Note: directory-separators have to + be specified as C-like backslashes and if you consider shell's + escape-mechanism, these in turn have to be escaped with backslashes ;-) + You will get 3 programs and a shared and static library. By default, the install-prefix is /usr/local, so you probably should add /usr/local/lib to your /etc/ld.so.conf and then run diff --git a/README.mjg b/README.mjg new file mode 100644 index 0000000..a557988 --- /dev/null +++ b/README.mjg @@ -0,0 +1,120 @@ +Retrofitting RFSV 16 to Fritz Elfert's plptools +=============================================== + +These notes updated 21/10/99 + + +I started modifying Fritz' plptools-0.3 with the intention of adding back the +RFSV16 support. Fritz then released 0.4, and so I re-patched 0.4, and did lots +more work, and merged in some patches from Pete Bentley. + +The result is this, plptools-0.4-mjg<x>. + +When it's finished, hopefully Fritz will merge it into the next official +release. + +Release Dates: +plptools-0.4-mjg1 on 23/09/99 +plptools-0.4-mjg2 on 04/10/99 +plptools-0.4-mjg3 on 07/10/99 +plptools-0.4-mjg4 on 10/10/99 +plptools-0.4-mjg5 on 21/10/99 (+ patch against 0.4 original) + +The changes to plptools-0.4 are: +* Now detects which version of the NCP protocol is in use, and records this: + this is how we detect whether the Psion is a Series 3 or Series 5. +* Makefiles updated to include the rfsv16 stuff, the rfsv base class, and the + rfsvfactory object. +* Instantiates either an RFSV32 or RFSV16 object to handle the file server + requests, based on the protocol version returned by the INFO command above. + There is an rfsvfactory object to make this easier in client programs. + This is used in plpftp and plpnfsd. This will obtain the NCP version number + over the socket, by announcing itself as "NCP$INFO.*". The correct RFSV class + will further announce itself as SYS$RFSV.* - this is stored in connectName. + RFSV objects have an opAttr method to output a correct attributes flag for each + protocol. +* Added --with-drive and --with-basedir to the configure.in script, and + include/defs.h.in. These are used in RFSV16, and plpftp now uses these, + instead of the DEFAULT_DRIVE AND DEFAULT_BASE_DIRECTORY of ftp.h +* ncpd/packet.h: verbose is now a short int, to allow packet debugging. +* Pete Bentley's changes. Fixes bogus definition of usleep(); plpftp compiles in + the absence of libreadline and libhistory; accept 3rd parameter in ppsocket is + signed not unsigned; -v all debugging option; (sun) link detection changes; + new PKT_DEBUG_HANDSHAKE debug level added; correct termios.h include for + Solaris; Solaris non-blocking fixes; move the fcntl for O_NONBLOCK; remove + O_NONBLOCK where needed; set SO_REUSEADDR for ncpd. +* Peter Cherriman's "1 hour out" fix (doesn't work for me though... could be my + PC clock) + +Some things to do: +* Finish rfsv16.cc: + fread, fwrite, fseek, copyFromPsion, copyToPsion, fsetsize, mktemp, + fcreatefile, freplacefile, fopendir, fsetmtime + +* Test everything with plpftp and plpnfsd. +* Remove read, write fully? +* Remove unused convertName method in plpftp/ftp.cc,h + +Adding RFSV16 back is still a work in progress.... stay tuned! + + +Building plptools for use with a Psion 3 +======================================== +./configure --with-speed=19200 --with-serial=/dev/ttyS1 --with-drive=M: +# Or whatever port you use. I use ttyS1, since ttyS0 is my mouse. +# The default speed is 115200 bps, which is only for the Lucky S5 owners. +# The S3c can take speeds up to 57600, but my RS232 protocol analyser can't - +# your mileage may vary. +make +make install +plpftp +# NFS access not finished yet + + +Tip for use with a Psion 3 +========================== +Turn the Psion's remote link on first, THEN run ncpd. + +Why this seems to help matters +------------------------------ +This seems to ensure that the Psion will send a request for the LINK.* process, +which is what we must detect to allow other connections to the NCP daemon. It +seems there may be a strange bug when you start ncpd, THEN start the Psion link +- the link request/acknowledge messages are exchanged correctly, followed by +valid INFO/NCP Protocol Version messages - and then the Psion attempts to +connect to the PC's SYS$RFSV.* - IMHO, it should start by attempting to connect +to LINK.* + +Philip Proudman's plp_1.7 always receives the LINK.* connect request, as do +other protocol implementations. + +I haven't managed to work out why the Psion starts by sending a SYS$RFSV.* +connect request with plptools, and not with other implementations, but the above +work-around gets round it. + + +Troubleshooting +=============== +Q. I can't build it on SuSE Linux. +A. You need the gppshare and libgpp packages. (Thanks to der.hans) + + +Acknowledgements +================ +This couldn't have been written without pioneering investigations into the link +protocol by Olaf Flebbe, Michael Pieper, and others. Philip Proudman beat me to +producing a decent, working PLP stack (Thanks, Philip ;-) and Fritz Elfert did +some excellent merging of Rudolf Koenig's p3nfs. Also thanks to the Majordomo +maintainers @geekstuff.co.uk, who host the linux-psion list. + +Finally, the RFSV16 re-merge would still be in my In-tray if my wife Angela +hadn't been away for the week, leaving me to code, and fend for myself. + +Thanks to Pete Bentley for ideas on proxying, his patches, suggestions for +improvement, and a loan Series 5 for testing against. + + +Viola! +-- +Matt Gumbley +matt@gumbley.demon.co.uk diff --git a/configure.in b/configure.in index a5fd29b..03e631b 100644 --- a/configure.in +++ b/configure.in @@ -2,10 +2,12 @@ AC_REVISION($ Revision: 0.1 $)dnl revision of this configure.in script AC_INIT(acinclude.m4) AM_CONFIG_HEADER(include/config.h) -AM_INIT_AUTOMAKE(plptools, 0.4) +AM_INIT_AUTOMAKE(plptools, 0.5) AM_PROG_LIBTOOL dnl Enable Mainatiner stuff +dnl **** NOTE **** Matt had to comment the following line out to get it to +dnl ************** build, and doesn't know why - YMMV. AM_MAINTAINER_MODE dnl checks for programs @@ -86,6 +88,26 @@ AC_ARG_WITH(port, ) AC_SUBST(DPORT) +AC_ARG_WITH(drive, + [ --with-drive=DRIVE override default Psion drive [AUTO]], + [ DDRIVE="$withval" + AC_MSG_RESULT(Overriding drive: $DDRIVE) ], + [ DDRIVE='AUTO' + AC_MSG_RESULT(Using default Psion drive: $DDRIVE) + ] +) +AC_SUBST(DDRIVE) + +AC_ARG_WITH(basedir, + [ --with-basedir=DIR override default Psion directory [\\\\]], + [ DBASEDIR="$withval" + AC_MSG_RESULT(Overriding directory: $DBASEDIR) ], + [ DBASEDIR="\\\\" + AC_MSG_RESULT(Using default Psion directory: $DBASEDIR) + ] +) +AC_SUBST(DBASEDIR) + AC_OUTPUT( Makefile lib/Makefile diff --git a/include/.cvsignore b/include/.cvsignore index 123a642..bd3c1d5 100644 --- a/include/.cvsignore +++ b/include/.cvsignore @@ -1,3 +1,4 @@ +stamp-h.in stamp-h config.h defs.h diff --git a/include/config.h.in b/include/config.h.in index 4932d0a..a9d3daa 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -1,9 +1,5 @@ /* include/config.h.in. Generated automatically from configure.in by autoheader. */ -#undef VERSION - -#undef PACKAGE - /* Define if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H @@ -33,3 +29,10 @@ /* Define if you have the socket library (-lsocket). */ #undef HAVE_LIBSOCKET + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + diff --git a/include/defs.h.in b/include/defs.h.in index 3c6fbce..ce5f68d 100644 --- a/include/defs.h.in +++ b/include/defs.h.in @@ -36,6 +36,8 @@ #define DDEV "@DDEV@" #define DSPEED @DSPEED@ #define DPORT @DPORT@ +#define DDRIVE "@DDRIVE@" +#define DBASEDIR "@DBASEDIR@" /* Debugging */ diff --git a/include/mp.h b/include/mp.h index ae2fe19..125ad80 100644 --- a/include/mp.h +++ b/include/mp.h @@ -122,7 +122,7 @@ extern char *index(), *rindex(), *strdup(); #endif /* mp_main.c */ -#if defined(hpux) || defined(__SVR4) +#if defined(hpux) || defined(__SVR4) && !defined(sun) /* HPUX 10.20 declares int usleep( useconds_t useconds); */ # ifndef HPUX10 extern void usleep __P((int usec)); diff --git a/lib/Makefile.am b/lib/Makefile.am index 27d5ea4..08df502 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,5 +1,9 @@ lib_LTLIBRARIES = libplp.la libplp_la_LDFLAGS = --debug -version-info 1:0:0 -libplp_la_SOURCES = bufferarray.cc bufferstore.cc iowatch.cc ppsocket.cc rfsv32.cc log.cc -EXTRA_DIST = bool.h bufferarray.h bufferstore.h iowatch.h ppsocket.h rfsv32.h log.h +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 +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 diff --git a/lib/bufferarray.cc b/lib/bufferarray.cc index 99b1811..4e922ed 100644 --- a/lib/bufferarray.cc +++ b/lib/bufferarray.cc @@ -2,6 +2,7 @@ // PLP - An implementation of the PSION link protocol // // Copyright (C) 1999 Philip Proudman +// extensions Copyright (C) 2000 Fritz Elfert <felfert@to.com> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -20,7 +21,8 @@ // e-mail philip.proudman@btinternet.com -#include <stdio.h> +#include <stream.h> +#include <iomanip.h> #include "bufferstore.h" #include "bufferarray.h" @@ -28,7 +30,7 @@ bufferArray::bufferArray() { len = 0; - lenAllocd = 5; + lenAllocd = ALLOC_MIN; buff = new bufferStore[lenAllocd]; } @@ -64,7 +66,7 @@ void bufferArray:: pushBuffer(const bufferStore & b) { if (len == lenAllocd) { - lenAllocd += 5; + lenAllocd += ALLOC_MIN; bufferStore *nb = new bufferStore[lenAllocd]; for (long i = 0; i < len; i++) { nb[i] = buff[i]; @@ -74,3 +76,92 @@ pushBuffer(const bufferStore & b) } buff[len++] = b; } + +void bufferArray:: +push(const bufferStore & b) +{ + if (len == lenAllocd) + lenAllocd += ALLOC_MIN; + bufferStore *nb = new bufferStore[lenAllocd]; + for (long i = len; i > 0; i--) { + nb[i] = buff[i-1]; + } + nb[0] = b; + delete[]buff; + buff = nb; + len++; +} + +bufferStore bufferArray:: +pop() +{ + return popBuffer(); +} + +void bufferArray:: +append(const bufferStore & b) +{ + pushBuffer(b); +} + +long bufferArray:: +length(void) +{ + return len; +} + +void bufferArray:: +clear(void) +{ + len = 0; + lenAllocd = ALLOC_MIN; + delete []buff; + buff = new bufferStore[lenAllocd]; +} + +bufferArray &bufferArray:: +operator =(const bufferArray & a) +{ + delete []buff; + len = a.len; + lenAllocd = a.lenAllocd; + buff = new bufferStore[lenAllocd]; + for (int i = 0; i < len; i++) + buff[i] = a.buff[i]; + return *this; +} + +bufferStore &bufferArray:: +operator [](const unsigned long index) +{ + return buff[index]; +} + +bufferArray &bufferArray:: +operator +(const bufferStore &a) +{ + append(a); + return *this; +} + +bufferArray &bufferArray:: +operator +(const bufferArray &a) +{ + lenAllocd += a.lenAllocd; + bufferStore *nb = new bufferStore[lenAllocd]; + for (int i = 0; i < len; i++) + nb[len + i] = buff[i]; + for (int i = 0; i < a.len; i++) + nb[len + i] = a.buff[i]; + len += a.len; + delete []buff; + buff = nb; + return *this; +} + +bufferArray &bufferArray:: +operator +=(const bufferStore &a) +{ + append(a); + return *this; +} diff --git a/lib/bufferarray.h b/lib/bufferarray.h index 4cb948e..fbf26f1 100644 --- a/lib/bufferarray.h +++ b/lib/bufferarray.h @@ -9,12 +9,27 @@ class bufferArray { bufferArray(); bufferArray(const bufferArray &a); ~bufferArray(); - void operator =(const bufferArray &a); - + bufferArray &operator =(const bufferArray &a); bool empty() const; - bufferStore popBuffer(); + + // 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); + private: + static const long ALLOC_MIN = 5; long len; long lenAllocd; bufferStore* buff; diff --git a/lib/bufferstore.cc b/lib/bufferstore.cc index 886b952..842e666 100644 --- a/lib/bufferstore.cc +++ b/lib/bufferstore.cc @@ -19,7 +19,8 @@ // // e-mail philip.proudman@btinternet.com -#include <stream.h> +#include <stream.h> +// That should be iostream.h, but it won't build on Sun WorkShop C++ 5.0 #include <iomanip.h> #include <string.h> @@ -48,7 +49,7 @@ bufferStore::bufferStore(const unsigned char*_buff, long _len) { start = 0; } -void bufferStore::operator =(const bufferStore &a) { +bufferStore &bufferStore::operator =(const bufferStore &a) { checkAllocd(a.getLen()); len = a.getLen(); memcpy(buff, a.getString(0), len); @@ -106,7 +107,7 @@ ostream &operator<<(ostream &s, const bufferStore &m) { if (c>=' ' && c <= 'z') s << c; } } - s<< ")"; + s<< ")" << dec << setw(0); return s; } @@ -144,6 +145,12 @@ void bufferStore::addStringT(const char* s) { addByte(0); } +void bufferStore::addBytes(const unsigned char* s, int l) { + checkAllocd(len + l); + memcpy(&buff[len], s, l); + len += l; +} + void bufferStore::addBuff(const bufferStore &s, long maxLen) { long l = s.getLen(); checkAllocd(len + l); diff --git a/lib/bufferstore.h b/lib/bufferstore.h index 4840689..df216c0 100644 --- a/lib/bufferstore.h +++ b/lib/bufferstore.h @@ -7,10 +7,10 @@ class ostream; class bufferStore { public: bufferStore(); - bufferStore(const unsigned char*buff, long len); + bufferStore(const unsigned char *, long); ~bufferStore(); - bufferStore(const bufferStore &a); - void operator =(const bufferStore &a); + bufferStore(const bufferStore &); + bufferStore &operator =(const bufferStore &); // Reading Utils unsigned long getLen() const; @@ -18,19 +18,20 @@ public: unsigned int getWord(long pos) const; unsigned int getDWord(long pos) const; const char* getString(long pos=0) const; - void discardFirstBytes(int n); - friend ostream &operator<<(ostream &s, const bufferStore &m); + void discardFirstBytes(int); + friend ostream &operator<<(ostream &, const bufferStore &); bool empty() const; // Writing utils void init(); - void init(const unsigned char*buff, long len); - void addByte(unsigned char c); - void addWord(int a); - void addDWord(long a); - void addString(const char* s); - void addStringT(const char* s); - void addBuff(const bufferStore &s, long maxLen=-1); + 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); private: void checkAllocd(long newLen); diff --git a/lib/ppsocket.cc b/lib/ppsocket.cc index c51c557..cb04919 100644 --- a/lib/ppsocket.cc +++ b/lib/ppsocket.cc @@ -30,6 +30,7 @@ #include <sys/time.h> #include <sys/types.h> #include <netinet/in.h> +#include <arpa/inet.h> #include "defs.h" #include "bool.h" @@ -126,7 +127,6 @@ printPeer() bool ppsocket:: connect(char *Peer, int PeerPort, char *Host, int HostPort) { - //**************************************************** //* If we aren't already bound set the host and bind * //**************************************************** @@ -172,13 +172,16 @@ listen(char *Host, int Port) m_LastError = lastErrorCode(); return (false); } + // Our accept member function relies on non-blocking accepts, + // so set the flag here (rather than every time around the loop) + fcntl(m_Socket, F_SETFL, O_NONBLOCK); return (true); } ppsocket *ppsocket:: accept(char *Peer, int MaxLen) { - unsigned int len; + socklen_t len; ppsocket *accepted; char *peer; @@ -197,7 +200,6 @@ accept(char *Peer, int MaxLen) //*********************** len = sizeof(struct sockaddr); - fcntl(m_Socket, F_SETFL, O_NONBLOCK); accepted->m_Socket =::accept(m_Socket, &accepted->m_PeerAddr, &len); if (accepted->m_Socket == INVALID_SOCKET) { @@ -209,6 +211,14 @@ accept(char *Peer, int MaxLen) //* Got a connection so fill in the other attributes * //**************************************************** + // Make sure the new socket hasn't inherited O_NONBLOCK + // from the accept socket + int flags = fcntl( accepted->m_Socket, F_GETFL, 0 ); + if( flags >= 0 ) { + flags &= ~O_NONBLOCK; + fcntl( accepted->m_Socket, F_SETFL, flags); + } + accepted->m_HostAddr = m_HostAddr; accepted->m_Bound = true; @@ -503,6 +513,11 @@ bindSocket(char *Host, int Port) return (false); } } + // Set SO_REUSEADDR + int one = 1; + if (setsockopt( m_Socket, SOL_SOCKET, SO_REUSEADDR, + (const char *) &one, sizeof(int)) < 0 ) + cerr << "Warning: Unable to set SO_REUSEADDR option\n"; // If a host name was supplied then use it if (!setHost(Host, Port)) { return (false); diff --git a/lib/rfsv.cc b/lib/rfsv.cc new file mode 100644 index 0000000..3b9dc6a --- /dev/null +++ b/lib/rfsv.cc @@ -0,0 +1,158 @@ +#include "rfsv.h" + +char *rfsv:: +opErr(long status) +{ + enum errs e = (enum errs) status; + switch (e) { + case E_PSI_GEN_NONE: + return "no error"; + case E_PSI_GEN_FAIL: + return "general"; + case E_PSI_GEN_ARG: + return "bad argument"; + case E_PSI_GEN_OS: + return "OS error"; + case E_PSI_GEN_NSUP: + return "not supported"; + case E_PSI_GEN_UNDER: + return "numeric underflow"; + case E_PSI_GEN_OVER: + return "numeric overflow"; + case E_PSI_GEN_RANGE: + return "numeric exception"; + case E_PSI_GEN_INUSE: + return "in use"; + case E_PSI_GEN_NOMEMORY: + return "out of memory"; + case E_PSI_GEN_NOSEGMENTS: + return "out of segments"; + case E_PSI_GEN_NOSEM: + return "out of semaphores"; + case E_PSI_GEN_NOPROC: + return "out of processes"; + case E_PSI_GEN_OPEN: + return "already open"; + case E_PSI_GEN_NOTOPEN: + return "not open"; + case E_PSI_GEN_IMAGE: + return "bad image"; + case E_PSI_GEN_RECEIVER: + return "receiver error"; + case E_PSI_GEN_DEVICE: + return "device error"; + case E_PSI_GEN_FSYS: + return "no filesystem"; + case E_PSI_GEN_START: + return "not ready"; + case E_PSI_GEN_NOFONT: + return "no font"; + case E_PSI_GEN_TOOWIDE: + return "too wide"; + case E_PSI_GEN_TOOMANY: + return "too many"; + case E_PSI_FILE_EXIST: + return "file already exists"; + case E_PSI_FILE_NXIST: + return "no such file"; + case E_PSI_FILE_WRITE: + return "write error"; + case E_PSI_FILE_READ: + return "read error"; + case E_PSI_FILE_EOF: + return "end of file"; + case E_PSI_FILE_FULL: + return "disk/serial read buffer full"; + case E_PSI_FILE_NAME: + return "invalid name"; + case E_PSI_FILE_ACCESS: + return "access denied"; + case E_PSI_FILE_LOCKED: + return "ressource locked"; + case E_PSI_FILE_DEVICE: + return "no such device"; + case E_PSI_FILE_DIR: + return "no such directory"; + case E_PSI_FILE_RECORD: + return "no such record"; + case E_PSI_FILE_RDONLY: + return "file is read-only"; + case E_PSI_FILE_INV: + return "invalid I/O operation"; + case E_PSI_FILE_PENDING: + return "I/O pending (not yet completed)"; + case E_PSI_FILE_VOLUME: + return "invalid volume name"; + case E_PSI_FILE_CANCEL: + return "cancelled"; + case E_PSI_FILE_ALLOC: + return "no memory for control block"; + case E_PSI_FILE_DISC: + return "unit disconnected"; + case E_PSI_FILE_CONNECT: + return "already connected"; + case E_PSI_FILE_RETRAN: + return "retransmission threshold exceeded"; + case E_PSI_FILE_LINE: + return "physical link failure"; + case E_PSI_FILE_INACT: + return "inactivity timer expired"; + case E_PSI_FILE_PARITY: + return "serial parity error"; + case E_PSI_FILE_FRAME: + return "serial framing error"; + case E_PSI_FILE_OVERRUN: + return "serial overrun error"; + case E_PSI_MDM_CONFAIL: + return "modem cannot connect to remote modem"; + case E_PSI_MDM_BUSY: + return "remote modem busy"; + case E_PSI_MDM_NOANS: + return "remote modem did not answer"; + case E_PSI_MDM_BLACKLIST: + return "number blacklisted by the modem"; + case E_PSI_FILE_NOTREADY: + return "drive not ready"; + case E_PSI_FILE_UNKNOWN: + return "unknown media"; + case E_PSI_FILE_DIRFULL: + return "directory full"; + case E_PSI_FILE_PROTECT: + return "write-protected"; + case E_PSI_FILE_CORRUPT: + return "media corrupt"; + case E_PSI_FILE_ABORT: + return "aborted operation"; + case E_PSI_FILE_ERASE: + return "failed to erase flash media"; + case E_PSI_FILE_INVALID: + return "invalid file for DBF system"; + case E_PSI_GEN_POWER: + return "power failure"; + case E_PSI_FILE_TOOBIG: + return "too big"; + case E_PSI_GEN_DESCR: + return "bad descriptor"; + case E_PSI_GEN_LIB: + return "bad entry point"; + case E_PSI_FILE_NDISC: + return "could not diconnect"; + case E_PSI_FILE_DRIVER: + return "bad driver"; + case E_PSI_FILE_COMPLETION: + return "operation not completed"; + case E_PSI_GEN_BUSY: + return "server busy"; + case E_PSI_GEN_TERMINATED: + return "terminated"; + case E_PSI_GEN_DIED: + return "died"; + case E_PSI_FILE_HANDLE: + return "bad handle"; + case E_PSI_NOT_SIBO: + return "invalid operation for RFSV16"; + default: + return "Unknown error"; + } +} + diff --git a/lib/rfsv.h b/lib/rfsv.h new file mode 100644 index 0000000..e6006ef --- /dev/null +++ b/lib/rfsv.h @@ -0,0 +1,151 @@ +#ifndef _rfsv_h_ +#define _rfsv_h_ + +class ppsocket; +class bufferStore; +class bufferArray; + +#define RFSV_SENDLEN 2000 + +typedef int (*cpCallback_t)(long); + +// Abstract base class of RFSV ; 16-bit and 32-bit variants implement this +// interface +class rfsv { + public: + virtual ~rfsv() {} + virtual void reset() = 0; + virtual void reconnect() = 0; + virtual long getStatus() = 0; + virtual const char *getConnectName() = 0; + virtual long fopen(long, const char *, long &) = 0; + virtual long mktemp(long *, char *) = 0; + virtual long fcreatefile(long, const char *, long &) = 0; + virtual long freplacefile(long, const char *, long &) = 0; + virtual long fopendir(long, const char *, long &) = 0; + virtual long fclose(long) = 0; + virtual long dir(const char *, bufferArray *) = 0; + virtual long fgetmtime(const char *, long *) = 0; + virtual long fsetmtime(const char *, long) = 0; + virtual long fgetattr(const char *, long *) = 0; + virtual long fgeteattr(const char *, long *, long *, long *) =0; + virtual long fsetattr(const char *, long, long) = 0; + virtual long dircount(const char *, long *) = 0; + virtual long devlist(long *) = 0; + virtual char *devinfo(int, long *, long *, long *, long *) = 0; + virtual char *opAttr(long) = 0; + virtual long opMode(long) = 0; + virtual long fread(long, unsigned char *, long) = 0; + virtual long fwrite(long, unsigned char *, long) = 0; + virtual long copyFromPsion(const char *, const char *, cpCallback_t) = 0; + virtual long copyToPsion(const char *, const char *, cpCallback_t) = 0; + virtual long fsetsize(long, long) = 0; + virtual long fseek(long, long, long) = 0; + virtual long mkdir(const char *) = 0; + virtual long rmdir(const char *) = 0; + virtual long rename(const char *, const char *) = 0; + virtual long remove(const char *) = 0; + + char *opErr(long); + + enum seek_mode { + PSI_SEEK_SET = 1, + PSI_SEEK_CUR = 2, + PSI_SEEK_END = 3 + }; + + enum open_flags { + PSI_O_RDONLY = 00, + PSI_O_WRONLY = 01, + PSI_O_RDWR = 02, + }; + + enum open_mode { + PSI_O_CREAT = 0100, + PSI_O_EXCL = 0200, + PSI_O_TRUNC = 01000, + PSI_O_APPEND = 02000, + }; + + enum errs { + E_PSI_GEN_NONE = 0, + E_PSI_GEN_FAIL = -1, + E_PSI_GEN_ARG = -2, + E_PSI_GEN_OS = -3, + E_PSI_GEN_NSUP = -4, + E_PSI_GEN_UNDER = -5, + E_PSI_GEN_OVER = -6, + E_PSI_GEN_RANGE = -7, + E_PSI_GEN_DIVIDE = -8, + E_PSI_GEN_INUSE = -9, + E_PSI_GEN_NOMEMORY = - 10, + E_PSI_GEN_NOSEGMENTS = -11, + E_PSI_GEN_NOSEM = -12, + E_PSI_GEN_NOPROC = -13, + E_PSI_GEN_OPEN = -14, + E_PSI_GEN_NOTOPEN = -15, + E_PSI_GEN_IMAGE = -16, + E_PSI_GEN_RECEIVER = -17, + E_PSI_GEN_DEVICE = -18, + E_PSI_GEN_FSYS = -19, + E_PSI_GEN_START = -20, + E_PSI_GEN_NOFONT = -21, + E_PSI_GEN_TOOWIDE = -22, + E_PSI_GEN_TOOMANY = -23, + E_PSI_FILE_EXIST = -32, + E_PSI_FILE_NXIST = -33, + E_PSI_FILE_WRITE = -34, + E_PSI_FILE_READ = -35, + E_PSI_FILE_EOF = -36, + E_PSI_FILE_FULL = -37, + E_PSI_FILE_NAME = -38, + E_PSI_FILE_ACCESS = -39, + E_PSI_FILE_LOCKED = -40, + E_PSI_FILE_DEVICE = -41, + E_PSI_FILE_DIR = -42, + E_PSI_FILE_RECORD = -43, + E_PSI_FILE_RDONLY = -44, + E_PSI_FILE_INV = -45, + E_PSI_FILE_PENDING = -46, + E_PSI_FILE_VOLUME = -47, + E_PSI_FILE_CANCEL = -48, + E_PSI_FILE_ALLOC = -49, + E_PSI_FILE_DISC = -50, + E_PSI_FILE_CONNECT = -51, + E_PSI_FILE_RETRAN = -52, + E_PSI_FILE_LINE = -53, + E_PSI_FILE_INACT = -54, + E_PSI_FILE_PARITY = -55, + E_PSI_FILE_FRAME = -56, + E_PSI_FILE_OVERRUN = -57, + E_PSI_MDM_CONFAIL = -58, + E_PSI_MDM_BUSY = -59, + E_PSI_MDM_NOANS = -60, + E_PSI_MDM_BLACKLIST = -61, + E_PSI_FILE_NOTREADY = -62, + E_PSI_FILE_UNKNOWN = -63, + E_PSI_FILE_DIRFULL = -64, + E_PSI_FILE_PROTECT = -65, + E_PSI_FILE_CORRUPT = -66, + E_PSI_FILE_ABORT = -67, + E_PSI_FILE_ERASE = -68, + E_PSI_FILE_INVALID = -69, + E_PSI_GEN_POWER = -100, + E_PSI_FILE_TOOBIG = -101, + E_PSI_GEN_DESCR = -102, + E_PSI_GEN_LIB = -103, + E_PSI_FILE_NDISC = -104, + E_PSI_FILE_DRIVER = -105, + E_PSI_FILE_COMPLETION = -106, + E_PSI_GEN_BUSY = -107, + E_PSI_GEN_TERMINATED = -108, + E_PSI_GEN_DIED = -109, + E_PSI_FILE_HANDLE = -110, + + // Special error code for "Operation not permitted in RFSV16" + E_PSI_NOT_SIBO = -200 + }; +}; + +#endif + diff --git a/lib/rfsv16.cc b/lib/rfsv16.cc new file mode 100644 index 0000000..9420b57 --- /dev/null +++ b/lib/rfsv16.cc @@ -0,0 +1,836 @@ +// +// RFSV16 - An implementation of the PSION SIBO RFSV Client protocol +// +// Copyright (C) 1999 Philip Proudman +// Modifications for plptools: +// Copyright (C) 1999 Matt J. Gumbley <matt@gumbley.demon.co.uk> +// Sources: rfsv32.cc by Fritz Elfert, and rfsv16.cc by Philip Proudman +// Descriptions of the RFSV16 protocol by Michael Pieper, Olaf Flebbe & Me. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// e-mail philip.proudman@btinternet.com + +#include <stream.h> +#include <stdlib.h> +#include <fstream.h> +#include <iomanip.h> +#include <time.h> +#include <string.h> + +#include "defs.h" +#include "bool.h" +#include "rfsv16.h" +#include "bufferstore.h" +#include "ppsocket.h" +#include "bufferarray.h" + +rfsv16::rfsv16(ppsocket *_skt) : serNum(0) +{ + skt = _skt; + reset(); +} + +// move to base class? +rfsv16::~rfsv16() +{ + bufferStore a; + a.addStringT("Close"); + if (status == E_PSI_GEN_NONE) + skt->sendBufferStore(a); + skt->closeSocket(); +} + +// move to base class? +void rfsv16:: +reconnect() +{ +cerr << "rfsv16::reconnect" << endl; + skt->closeSocket(); + skt->reconnect(); + serNum = 0; + reset(); +} + +// move to base class? +void rfsv16:: +reset() +{ +cerr << "rfsv16::reset" << endl; + bufferStore a; + status = E_PSI_FILE_DISC; + a.addStringT(getConnectName()); + if (skt->sendBufferStore(a)) { + if (skt->getBufferStore(a) == 1) { + if (!strcmp(a.getString(0), "Ok")) + status = E_PSI_GEN_NONE; + } + } +} + +// move to base class? +long rfsv16:: +getStatus() +{ + return status; +} + +// move to base class? +const char *rfsv16:: +getConnectName() +{ + return "SYS$RFSV.*"; +} + +int rfsv16:: +convertName(const char* orig, char *retVal) +{ + int len = strlen(orig); + char *temp = new char [len+1]; + + // FIXME: need to return 1 if OOM? + for (int i=0; i <= len; i++) { + if (orig[i] == '/') + temp[i] = '\\'; + else + temp[i] = orig[i]; + } + + if (len == 0 || temp[1] != ':') { + // We can automatically supply a drive letter + strcpy(retVal, DDRIVE); + + if (len == 0 || temp[0] != '\\') { + strcat(retVal, DBASEDIR); + } + else { + retVal[strlen(retVal)-1] = 0; + } + + strcat(retVal, temp); + } + else { + strcpy(retVal, temp); + } + + delete [] temp; + cout << retVal << endl; + return 0; +} + +long rfsv16:: +fopen(long attr, const char *name, long &handle) +{ + bufferStore a; + char realName[200]; + int rv = convertName(name, realName); + if (rv) return (long)rv; + + // FIXME: anything that calls fopen should NOT do the name + // conversion - it's just done here. + + a.addWord(attr & 0xFFFF); + a.addString(realName); + a.addByte(0x00); // Needs to be manually Null-Terminated. + if (!sendCommand(FOPEN, a)) + 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); + return 0; + } + // cerr << "fopen: Unknown response (" << attr << "," << name << ") " << a <<endl; + return res; +} + +// internal +long rfsv16:: +mktemp(long *handle, char *tmpname) +{ +cerr << "rfsv16::mktemp ***" << endl; + return 0; +} + +// internal and external +long rfsv16:: +fcreatefile(long attr, const char *name, long &handle) +{ +cerr << "rfsv16::fcreatefile ***" << endl; + return 0; +} + +// 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; +} + +// internal +long rfsv16:: +fopendir(long attr, const char *name, long &handle) +{ +cerr << "rfsv16::fopendir ***" << endl; + return 0; +} + +long rfsv16:: +fclose(long fileHandle) +{ + bufferStore a; + 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; +} + +long rfsv16:: +dir(const char *dirName, bufferArray * files) +{ + long fileHandle; + long res; + + long status = fopen(P_FDIR, dirName, fileHandle); + if (status != 0) { + return status; + } + + while (1) { + bufferStore a; + a.addWord(fileHandle & 0xFFFF); + if (!sendCommand(FDIRREAD, a)) + return E_PSI_FILE_DISC; + res = getResponse(a); + if (res) + break; + a.discardFirstBytes(4); // Don't know what these mean! + while (a.getLen() > 16) { + int version = a.getWord(0); + if (version != 2) { + cerr << "dir: not version 2" << endl; + return 1; + } + int status = a.getWord(2); + long size = a.getDWord(4); + long date = a.getDWord(8); + const char *s = a.getString(16); + a.discardFirstBytes(17+strlen(s)); + + bufferStore temp; + temp.addDWord(date); + temp.addDWord(size); + temp.addDWord((long)status); + temp.addStringT(s); + files->pushBuffer(temp); + } + } + if ((short int)res == E_PSI_FILE_EOF) + res = 0; + fclose(fileHandle); + return res; +} + +char * rfsv16:: +opAttr(long attr) +{ + static char buf[11]; + buf[0] = ((attr & rfsv16::P_FAWRITE) ? 'w' : '-'); + buf[1] = ((attr & rfsv16::P_FAHIDDEN) ? 'h' : '-'); + buf[2] = ((attr & rfsv16::P_FASYSTEM) ? 's' : '-'); + buf[3] = ((attr & rfsv16::P_FAVOLUME) ? 'v' : '-'); + buf[4] = ((attr & rfsv16::P_FADIR) ? 'd' : '-'); + buf[5] = ((attr & rfsv16::P_FAMOD) ? 'm' : '-'); + buf[6] = ((attr & rfsv16::P_FAREAD) ? 'r' : '-'); + buf[7] = ((attr & rfsv16::P_FAEXEC) ? 'x' : '-'); + buf[8] = ((attr & rfsv16::P_FASTREAM) ? 'b' : '-'); + buf[9] = ((attr & rfsv16::P_FATEXT) ? 't' : '-'); + buf[10] = '\0'; + return (char *) (&buf); +} + + +long rfsv16:: +opMode(long mode) +{ + long ret = 0; + + ret |= ((mode & 03) == PSI_O_RDONLY) ? 0 : P_FUPDATE; + ret |= (mode & PSI_O_TRUNC) ? P_FREPLACE : 0; + ret |= (mode & PSI_O_CREAT) ? P_FCREATE : 0; + ret |= (mode & PSI_O_APPEND) ? P_FAPPEND : 0; + ret |= (mode & PSI_O_EXCL) ? 0 : P_FSHARE; + return ret; +} + +long rfsv16:: +fgetmtime(const char *name, long *mtime) +{ +cerr << "rfsv16::fgetmtime" << endl; + // NB: fgetattr, fgeteattr is almost identical... + bufferStore a; + char realName[200]; + int rv = convertName(name, realName); + if (rv) return rv; + a.addString(realName); + a.addByte(0x00); // needs to be null-terminated, + // and this needs sending in the length word. + if (!sendCommand(FINFO, a)) + return E_PSI_FILE_DISC; + + long res = getResponse(a); + if (res != 0) + 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); + } + cerr << "fgetmtime: Unknown response (" << name << ") " << a <<endl; + return 1; +} + +long rfsv16:: +fsetmtime(const char *name, long mtime) +{ +cerr << "rfsv16::fsetmtime ***" << endl; + // I don't think there's a protocol frame that allows us to set the + // modification time. SFDATE allows setting of creation time... + return E_PSI_NOT_SIBO; +} + +long rfsv16:: +fgetattr(const char *name, long *attr) +{ + // NB: fgetmtime, fgeteattr are almost identical... + bufferStore a; + char realName[200]; + int rv = convertName(name, realName); + if (rv) return rv; + a.addString(realName); + a.addByte(0x00); // needs to be null-terminated, + // and this needs sending in the length word. + if (!sendCommand(FINFO, a)) + return E_PSI_FILE_DISC; + + long res = getResponse(a); + if (res != 0) + 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); + } + cerr << "fgetattr: Unknown response (" << name << ") " << a <<endl; + return 1; +} + +long rfsv16:: +fgeteattr(const char *name, long *attr, long *size, long *time) +{ + bufferStore a; + char realName[200]; + int rv = convertName(name, realName); + if (rv) return rv; + a.addString(realName); + a.addByte(0x00); // needs to be null-terminated, + // and this needs sending in the length word. + if (!sendCommand(FINFO, a)) + return E_PSI_FILE_DISC; + + long res = getResponse(a); + if (res != 0) + return res; + if (a.getLen() == 2) { + cerr << "fgeteattr: Error " << a.getWord(0) << " on file " << name << endl; + return 1; + } + 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); + } + cerr << "fgeteattr: Unknown response (" << name << ") " << a <<endl; + return 1; +} + +long rfsv16:: +fsetattr(const char *name, long seta, long unseta) +{ +cerr << "rfsv16::fsetattr" << endl; + // seta are attributes to set; unseta are attributes to unset. Need to + // turn this into attributes to change state and a bit mask. + // 210000 + // 008421 + // a shr + long statusword = seta & (~ unseta); + statusword ^= 0x0000001; // r bit is inverted + long bitmask = seta | unseta; + // cerr << "seta is " << hex << setw(2) << setfill('0') << seta << endl; + // cerr << "unseta is " << hex << setw(2) << setfill('0') << unseta << endl; + // cerr << "statusword is " << hex << setw(2) << setfill('0') << statusword << endl; + // cerr << "bitmask is " << hex << setw(2) << setfill('0') << bitmask << endl; + bufferStore a; + a.addWord(statusword & 0xFFFF); + a.addWord(bitmask & 0xFFFF); + a.addString(name); + a.addByte(0x00); // needs to be null-terminated, + // and this needs sending in the length word. + if (!sendCommand(SFSTAT, a)) + return E_PSI_FILE_DISC; + return getResponse(a); +} + +long rfsv16:: +dircount(const char *name, long *count) +{ + long fileHandle; + long res; + *count = 0; + + long status = fopen(P_FDIR, name, fileHandle); + if (status != 0) { + return status; + } + + while (1) { + bufferStore a; + a.addWord(fileHandle & 0xFFFF); + if (!sendCommand(FDIRREAD, a)) + return E_PSI_FILE_DISC; + res = getResponse(a); + if (res) + break; + a.discardFirstBytes(4); // Don't know what these mean! + while (a.getLen() > 16) { + int version = a.getWord(0); + if (version != 2) { + cerr << "dir: not version 2" << endl; + return 1; + } + // int status = a.getWord(2); + // long size = a.getDWord(4); + // long date = a.getDWord(8); + const char *s = a.getString(16); + a.discardFirstBytes(17+strlen(s)); + (*count)++; + } + } + if ((short int)res == E_PSI_FILE_EOF) + res = 0; + fclose(fileHandle); + return res; +} + +long rfsv16:: +devlist(long *devbits) +{ + long res; + long fileHandle; + *devbits = 0; + + // The following is taken from a trace between a Series 3c and PsiWin. + // Hope it works! We PARSE to find the correct node, then FOPEN + // (P_FDEVICE) this, FDEVICEREAD each entry, setting the appropriate + // drive-letter-bit in devbits, then FCLOSE. + + bufferStore a; + a.init(); + a.addByte(0x00); // no Name 1 + a.addByte(0x00); // no Name 2 + a.addByte(0x00); // no Name 3 + if (!sendCommand(PARSE, a)) + return E_PSI_FILE_DISC; + res = getResponse(a); + if (res) + return res; + + // Find the drive to FOPEN + char name[4] = { 'x', ':', '\\', '\0' } ; + a.discardFirstBytes(8); // 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); + if (status != 0) { + return status; + } + while (1) { + bufferStore a; + a.init(); + a.addWord(fileHandle & 0xFFFF); + if (!sendCommand(FDEVICEREAD, a)) + return E_PSI_FILE_DISC; + res = getResponse(a); + if (res) + break; + a.discardFirstBytes(2); // Result + int version = a.getWord(0); + if (version != 2) { + cerr << "devlist: not version 2" << endl; + return 1; // FIXME + } + char drive = a.getByte(64); + if (drive >= 'A' && drive <= 'Z') { + int shift = (drive - 'A'); + (*devbits) |= (long) ( 1 << shift ); + } + else { + cerr << "devlist: non-alphabetic drive letter (" + << drive << ")" << endl; + } + } + if ((short int)res == E_PSI_FILE_EOF) + res = 0; + fclose(fileHandle); + return res; +} + +char *rfsv16:: +devinfo(int devnum, long *vfree, long *vtotal, long *vattr, + long *vuniqueid) +{ + bufferStore a; + long res; + long fileHandle; + + // Again, this is taken from an excahnge between PsiWin and a 3c. + // For each drive, we PARSE with its drive letter to get a response + // (which we ignore), then do a STATUSDEVICE to get the info. + + a.init(); + a.addByte((char) (devnum + 'A')); // Name 1 + a.addByte(':'); + a.addByte(0x00); + a.addByte(0x00); // No name 2 + a.addByte(0x00); // No name 3 + if (!sendCommand(PARSE, a)) + return NULL; + res = getResponse(a); + if (res) { + // cerr << "devinfo PARSE res is " << dec << (signed short int) res << endl; + return NULL; + } + + a.init(); + a.addByte((char) (devnum + 'A')); // Name 1 + a.addByte(':'); + a.addByte('\\'); + a.addByte(0x00); + if (!sendCommand(STATUSDEVICE, a)) + return NULL; + res = getResponse(a); + if (res) { + // 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); + long free = a.getDWord(10); + const char *volume = a.getString(14); + int battery = a.getWord(30); + const char *devicename = a.getString(62); + *vfree = free; + *vtotal = size; + *vattr = type; + *vuniqueid = 0; + static char name[2] = { 'x', '\0' }; + name[0] = (char) (devnum + 'A'); + return strdup(name); +} + +bool rfsv16:: +sendCommand(enum commands cc, bufferStore & data) +{ + bool result; + bufferStore a; + a.addWord(cc); + a.addWord(data.getLen()); + a.addBuff(data); + result = skt->sendBufferStore(a); + if (!result) + status = E_PSI_FILE_DISC; + return result; +} + + +long rfsv16:: +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 && + data.getWord(2) == data.getLen()-4) { + data.discardFirstBytes(4); + long ret = data.getWord(0); + return ret; + } else + status = E_PSI_FILE_DISC; + cerr << "rfsv16::getResponse: duff response. Size field:" << +data.getWord(2) << " Frame size:" << data.getLen()-4 << " Result field:" << +data.getWord(4) << endl; + return status; +} + +char * rfsv16:: +opErr(long status) +{ +cerr << "rfsv16::opErr 0x" << hex << setfill('0') << setw(4) + << status << " (" << dec << (signed short int)status << ")" << endl; + return rfsv::opErr(status); +} + +long rfsv16:: +fread(long handle, unsigned char *buf, long len) +{ +cerr << "rfsv16::fread ***" << endl; + 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 + // 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); + sendCommand(FREAD, a); + long res = getResponse(a); + remaining -= a.getLen(); +// copy the data to buf + +cerr << "fread getResponse returned " << dec<< (signed short int) res << " data: " << a << dec <<endl; + if (res) { + return res; + } + } + return len; +} + +long rfsv16:: +fwrite(long handle, unsigned char *buf, long len) +{ +cerr << "rfsv16::fwrite ***" << endl; + return 0; +} + +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]; + if ((len = fread(handle, buf, sizeof(buf))) > 0) + op.write(buf, len); + if (cb) { + if (!cb(len)) { + len = E_PSI_FILE_CANCEL; + break; + } + } + } while (len > 0); + + fclose(handle); + op.close(); + return len; +} + +long rfsv16:: +copyToPsion(const char *from, const char *to, cpCallback_t cb) +{ +cerr << "rfsv16::copyToPsion" << endl; + long handle; + long res; + + ifstream ip(from); + if (!ip) + return E_PSI_FILE_NXIST; + res = fcreatefile(P_FSTREAM | P_FUPDATE, to, handle); + if (res != 0) { + res = freplacefile(P_FSTREAM | P_FUPDATE, to, handle); + if (res != 0) + return res; + } + unsigned char *buff = new unsigned char[RFSV_SENDLEN]; + int total = 0; + while (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 = 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; +} + +/* + * Unix-like implementation off fseek with one + * exception: If seeking beyond eof, the gap + * contains garbage instead of zeroes. + */ +long rfsv16:: +fseek(long handle, long pos, long mode) +{ +cerr << "rfsv16::fseek ***" << endl; + return 0; +} + +long rfsv16:: +mkdir(const char* dirName) +{ + char realName[200]; + int rv = convertName(dirName, realName); + if (rv) return rv; + bufferStore a; + a.addString(realName); + a.addByte(0x00); // needs to be null-terminated, + // and this needs sending in the length word. + sendCommand(MKDIR, a); + long res = getResponse(a); + if (!res && a.getLen() == 2) { + // Correct response + return a.getWord(0); + } + cerr << "Unknown response from mkdir "<< a <<endl; + return 1; +} + +long rfsv16:: +rmdir(const char *dirName) +{ + // There doesn't seem to be an RMDIR command, but DELETE works. We + // should probably check to see if the file is a directory first! + return remove(dirName); +} + +long rfsv16:: +rename(const char *oldName, const char *newName) +{ +cerr << "rfsv16::rename ***" << endl; + char realOldName[200]; + int rv = convertName(oldName, realOldName); + if (rv) return rv; + char realNewName[200]; + rv = convertName(newName, realNewName); + if (rv) return rv; + bufferStore a; + a.addString(realOldName); + a.addByte(0x00); // needs to be null-terminated, + // and this needs sending in the length word. + a.addString(realNewName); + a.addByte(0x00); // needs to be null-terminated, + // and this needs sending in the length word. + sendCommand(RENAME, a); + long res = getResponse(a); + if (!res && a.getLen() == 2) { + // Correct response + return a.getWord(0); + } + cerr << "Unknown response from rename "<< a <<endl; + return 1; +} + +long rfsv16:: +remove(const char* psionName) +{ + char realName[200]; + int rv = convertName(psionName, realName); + if (rv) return rv; + bufferStore a; + a.addString(realName); + a.addByte(0x00); // needs to be null-terminated, + // and this needs sending in the length word. + sendCommand(DELETE, a); + long res = getResponse(a); + if (!res && a.getLen() == 2) { + // Correct response + return a.getWord(0); + } + cerr << "Unknown response from delete "<< a <<endl; + return 1; +} + + diff --git a/lib/rfsv16.h b/lib/rfsv16.h new file mode 100644 index 0000000..175e540 --- /dev/null +++ b/lib/rfsv16.h @@ -0,0 +1,127 @@ +#ifndef _rfsv16_h_ +#define _rfsv16_h_ + +#include "rfsv.h" + +class rfsv16 : public rfsv { + public: + rfsv16(ppsocket *); + ~rfsv16(); + void reset(); // these 2 added + void reconnect(); + + // these are the original publics + long dir(const char *, bufferArray *); + /*long read(const char* psionName, const char* localName); + long write(const char* localName, const char* psionName);*/ + long mkdir(const char *); + + // these are FS' promotions + long dircount(const char *, long *); + long copyFromPsion(const char *, const char *, cpCallback_t); + long copyToPsion(const char *, const char *, cpCallback_t); + long rmdir(const char *); + long remove(const char *); // MJG: was this del? FE: yes + long rename(const char *, const char *); + long mktemp(long *, char *); + long fgeteattr(const char *, long *, long *, long *); + long fgetattr(const char *, long *); + long fsetattr(const char *, long seta, long unseta); + long fgetmtime(const char *, long *); + long fsetmtime(const char *, long); + long fopendir(long, const char *, long &); + long fopen(long, const char *, long &); + long fcreatefile(long, const char *, long &); + long freplacefile(long, const char *, long &); + long fseek(long, long, long); + long fread(long, unsigned char *, long); + long fwrite(long, unsigned char *, long); + long fsetsize(long, long); + long fclose(long); + + long devlist(long *); + char *devinfo(int, long *, long *, long *, long *); + long getStatus(); + char *opErr(long); + char *opAttr(long); + long opMode(long); + +private: + enum commands { + FOPEN = 0, // File Open + FCLOSE = 2, // File Close + FREAD = 4, // File Read + FDIRREAD = 6, // Read Directory entries + FDEVICEREAD = 8, // Device Information + FWRITE = 10, // File Write + FSEEK = 12, // File Seek + FFLUSH = 14, // Flush + FSETEOF = 16, + RENAME = 18, + DELETE = 20, + FINFO = 22, + SFSTAT = 24, + PARSE = 26, + MKDIR = 28, + OPENUNIQUE = 30, + STATUSDEVICE = 32, + PATHTEST = 34, + STATUSSYSTEM = 36, + CHANGEDIR = 38, + SFDATE = 40, + RESPONSE = 42 + }; + + enum fopen_attrib { + P_FOPEN = 0x0000, /* Open file */ + P_FCREATE = 0x0001, /* Create file */ + P_FREPLACE = 0x0002, /* Replace file */ + P_FAPPEND = 0x0003, /* Append records */ + P_FUNIQUE = 0x0004, /* Unique file open */ + P_FSTREAM = 0x0000, /* Stream access to a binary file */ + P_FSTREAM_TEXT = 0x0010, /* Stream access to a text file */ + P_FTEXT = 0x0020, /* Record access to a text file */ + P_FDIR = 0x0030, /* Record access to a directory file */ + P_FFORMAT = 0x0040, /* Format a device */ + P_FDEVICE = 0x0050, /* Record access to device name list */ + P_FNODE = 0x0060, /* Record access to node name list */ + P_FUPDATE = 0x0100, /* Read and write access */ + P_FRANDOM = 0x0200, /* Random access */ + P_FSHARE = 0x0400 /* File can be shared */ + }; + + enum status_enum { + P_FAWRITE = 0x0001, /* can the file be written to? */ + P_FAHIDDEN = 0x0002, /* set if file is hidden */ + P_FASYSTEM = 0x0004, /* set if file is a system file */ + P_FAVOLUME = 0x0008, /* set if the name is a volume name */ + P_FADIR = 0x0010, /* set if file is a directory file */ + P_FAMOD = 0x0020, /* has the file been modified? */ + P_FAREAD = 0x0100, /* can the file be read? */ + P_FAEXEC = 0x0200, /* is the file executable? */ + P_FASTREAM = 0x0400, /* is the file a byte stream file? */ + P_FATEXT = 0x0800 /* is it a text file? */ + }; + + const char *getConnectName(); + + // File handlers + //long fopen(fopen_attrib a, const char* file, int &handle); // returns status 0=OK + //long fclose(int fileHandle); + + // Miscellaneous + int convertName(const char*, char *); + + // Communication + bool sendCommand(enum commands, bufferStore &); + long getResponse(bufferStore &); + + // Vars + ppsocket *skt; + // MJG: not sure what these are yet + int serNum; + long status; // current connection status + int tDiff; // don't think this is used anywhere +}; + +#endif diff --git a/lib/rfsv32.cc b/lib/rfsv32.cc index 447a693..d4df37f 100644 --- a/lib/rfsv32.cc +++ b/lib/rfsv32.cc @@ -33,8 +33,6 @@ #include "ppsocket.h" #include "bufferarray.h" -#define RFSV_SENDLEN 230 - rfsv32::rfsv32(ppsocket * _skt) : serNum(0) { skt = _skt; @@ -45,7 +43,7 @@ rfsv32::~rfsv32() { bufferStore a; a.addStringT("Close"); - if (status == PSI_ERR_NONE) + if (status == E_PSI_GEN_NONE) skt->sendBufferStore(a); skt->closeSocket(); } @@ -63,12 +61,12 @@ void rfsv32:: reset() { bufferStore a; - status = PSI_ERR_DISCONNECTED; + status = E_PSI_FILE_DISC; a.addStringT(getConnectName()); if (skt->sendBufferStore(a)) { if (skt->getBufferStore(a) == 1) { if (!strcmp(a.getString(0), "Ok")) - status = PSI_ERR_NONE; + status = E_PSI_GEN_NONE; } } } @@ -82,7 +80,7 @@ getStatus() const char *rfsv32:: getConnectName() { - return "SYS$RFSV.*"; + return "SYS$RFSV"; } char *rfsv32:: @@ -105,7 +103,7 @@ fopen(long attr, const char *name, long &handle) a.addString(n); free(n); if (!sendCommand(OPEN_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; long res = getResponse(a); if (!res && a.getLen() == 4) { handle = a.getDWord(0); @@ -119,7 +117,7 @@ mktemp(long *handle, char *tmpname) { bufferStore a; if (!sendCommand(TEMP_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; long res = getResponse(a); if (res == 0) { *handle = a.getDWord(0); @@ -138,7 +136,7 @@ fcreatefile(long attr, const char *name, long &handle) a.addString(n); free(n); if (!sendCommand(CREATE_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; long res = getResponse(a); if (!res && a.getLen() == 4) handle = a.getDWord(0); @@ -155,7 +153,7 @@ freplacefile(long attr, const char *name, long &handle) a.addString(n); free(n); if (!sendCommand(REPLACE_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; long res = getResponse(a); if (!res && a.getLen() == 4) handle = a.getDWord(0); @@ -172,7 +170,7 @@ fopendir(long attr, const char *name, long &handle) a.addString(n); free(n); if (!sendCommand(OPEN_DIR, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; long res = getResponse(a); if (!res && a.getLen() == 4) handle = a.getDWord(0); @@ -185,7 +183,7 @@ fclose(long handle) bufferStore a; a.addDWord(handle); if (!sendCommand(CLOSE_HANDLE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; return getResponse(a); } @@ -206,6 +204,7 @@ micro2time(unsigned long microHi, unsigned long microLo) micro -= pes; micro += EPOCH_DIFF_SECS; micro -= EPOCH_2H; + micro += 3600; /* 1 hour PJC */ return (long) micro; } @@ -218,6 +217,7 @@ time2micro(unsigned long time, unsigned long µHi, unsigned long µLo) micro += pes; micro -= EPOCH_DIFF_SECS; micro += EPOCH_2H; + micro -= 3600; /* 1 hour PJC */ micro *= (unsigned long long)1000000; microLo = (micro & (unsigned long long)0x0FFFFFFFF); micro >>= 32; @@ -228,7 +228,7 @@ long rfsv32:: dir(const char *name, bufferArray * files) { long handle; - long res = fopendir(PSI_ATTR_HIDDEN | PSI_ATTR_SYSTEM | PSI_ATTR_DIRECTORY, name, handle); + long res = fopendir(EPOC_ATTR_HIDDEN | EPOC_ATTR_SYSTEM | EPOC_ATTR_DIRECTORY, name, handle); if (res != 0) return res; @@ -236,7 +236,7 @@ dir(const char *name, bufferArray * files) bufferStore a; a.addDWord(handle); if (!sendCommand(READ_DIR, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; res = getResponse(a); if (res) break; @@ -270,12 +270,40 @@ dir(const char *name, bufferArray * files) a.discardFirstBytes(d); } } - if (res == PSI_ERR_EoF) + if (res == E_PSI_FILE_EOF) res = 0; fclose(handle); return res; } +// beware this returns static data +char * rfsv32:: +opAttr(long attr) +{ + static char buf[10]; + buf[0] = ((attr & rfsv32::EPOC_ATTR_DIRECTORY) ? 'd' : '-'); + buf[1] = ((attr & rfsv32::EPOC_ATTR_RONLY) ? '-' : 'w'); + buf[2] = ((attr & rfsv32::EPOC_ATTR_HIDDEN) ? 'h' : '-'); + buf[3] = ((attr & rfsv32::EPOC_ATTR_SYSTEM) ? 's' : '-'); + buf[4] = ((attr & rfsv32::EPOC_ATTR_ARCHIVE) ? 'a' : '-'); + buf[5] = ((attr & rfsv32::EPOC_ATTR_VOLUME) ? 'v' : '-'); + buf[6] = ((attr & rfsv32::EPOC_ATTR_NORMAL) ? 'n' : '-'); + buf[7] = ((attr & rfsv32::EPOC_ATTR_TEMPORARY) ? 't' : '-'); + buf[8] = ((attr & rfsv32::EPOC_ATTR_COMPRESSED) ? 'c' : '-'); + buf[9] = '\0'; + return (char *) (&buf); +} + +long rfsv32:: +opMode(long mode) +{ + long ret = 0; + + ret |= (((mode & 03) == PSI_O_RDONLY) ? 0 : EPOC_OMODE_READ_WRITE); + ret |= (mode & PSI_O_EXCL) ? 0 : EPOC_OMODE_SHARE_READERS; + return ret; +} + long rfsv32:: fgetmtime(const char *name, long *mtime) { @@ -285,7 +313,7 @@ fgetmtime(const char *name, long *mtime) a.addString(n); free(n); if (!sendCommand(MODIFIED, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; long res = getResponse(a); if (res != 0) return res; @@ -306,7 +334,7 @@ fsetmtime(const char *name, long mtime) a.addString(n); free(n); if (!sendCommand(SET_MODIFIED, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; long res = getResponse(a); if (res != 0) return res; @@ -322,7 +350,7 @@ fgetattr(const char *name, long *attr) a.addString(n); free(n); if (!sendCommand(ATT, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; long res = getResponse(a); if (res != 0) return res; @@ -339,7 +367,7 @@ fgeteattr(const char *name, long *attr, long *size, long *time) a.addString(n); free(n); if (!sendCommand(REMOTE_ENTRY, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; long res = getResponse(a); if (res != 0) return res; @@ -367,7 +395,7 @@ fsetattr(const char *name, long seta, long unseta) a.addString(n); free(n); if (!sendCommand(SET_ATT, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; return getResponse(a); } @@ -375,7 +403,7 @@ long rfsv32:: dircount(const char *name, long *count) { long handle; - long res = fopendir(PSI_ATTR_HIDDEN | PSI_ATTR_SYSTEM | PSI_ATTR_DIRECTORY, name, handle); + long res = fopendir(EPOC_ATTR_HIDDEN | EPOC_ATTR_SYSTEM | EPOC_ATTR_DIRECTORY, name, handle); *count = 0; if (res != 0) return res; @@ -384,7 +412,7 @@ dircount(const char *name, long *count) bufferStore a; a.addDWord(handle); if (!sendCommand(READ_DIR, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; res = getResponse(a); if (res) break; @@ -400,7 +428,7 @@ dircount(const char *name, long *count) } } fclose(handle); - if (res == PSI_ERR_EoF) + if (res == E_PSI_FILE_EOF) res = 0; return res; } @@ -412,7 +440,7 @@ devlist(long *devbits) long res; if (!sendCommand(GET_DRIVE_LIST, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; res = getResponse(a); *devbits = 0; if ((res == 0) && (a.getLen() == 26)) { @@ -451,9 +479,9 @@ devinfo(int devnum, long *vfree, long *vtotal, long *vattr, bool rfsv32:: sendCommand(enum commands cc, bufferStore & data) { - if (status == PSI_ERR_DISCONNECTED) { + if (status == E_PSI_FILE_DISC) { reconnect(); - if (status == PSI_ERR_DISCONNECTED) + if (status == E_PSI_FILE_DISC) return false; } bool result; @@ -467,7 +495,7 @@ sendCommand(enum commands cc, bufferStore & data) a.addBuff(data); result = skt->sendBufferStore(a); if (!result) - status = PSI_ERR_DISCONNECTED; + status = E_PSI_FILE_DISC; return result; } @@ -478,155 +506,14 @@ getResponse(bufferStore & data) data.getWord(0) == 0x11) { long ret = data.getDWord(4); data.discardFirstBytes(8); - return ret; + return err2psierr(ret); } else - status = PSI_ERR_DISCONNECTED; + status = E_PSI_FILE_DISC; return status; } -char * rfsv32:: -opErr(long status) -{ - enum errs e = (enum errs) status; - switch (e) { - case PSI_ERR_NONE: - return ""; - case PSI_ERR_NOT_FOUND: - return "not found"; - case PSI_ERR_GENERAL: - return "general"; - break; - case PSI_ERR_CANCEL: - return "cancelled"; - break; - case PSI_ERR_NO_MEMORY: - return "out of memory"; - break; - case PSI_ERR_NOT_SUPPORTED: - return "unsupported"; - break; - case PSI_ERR_ARGUMENT: - return "bad argument"; - break; - case PSI_ERR_TOTAL_LOSS_OF_PRECISION: - return "total loss of precision"; - break; - case PSI_ERR_BAD_HANDLE: - return "bad handle"; - break; - case PSI_ERR_OVERFLOW: - return "overflow"; - break; - case PSI_ERR_UNDERFLOW: - return "underflow"; - break; - case PSI_ERR_ALREADY_EXISTS: - return "file already exists"; - break; - case PSI_ERR_PATH_NOT_FOUND: - return "path not found"; - break; - case PSI_ERR_DIED: - return "DIED"; - break; - case PSI_ERR_IN_USE: - return "resource in use"; - break; - case PSI_ERR_SERVER_TERMINATED: - return "server terminated"; - break; - case PSI_ERR_SERVER_BUSY: - return "server busy"; - break; - case PSI_ERR_COMPLETION: - return "completed"; - break; - case PSI_ERR_NOT_READY: - return "not ready"; - break; - case PSI_ERR_UNKNOWN: - return "unknown"; - break; - case PSI_ERR_CORRUPT: - return "corrupt"; - break; - case PSI_ERR_ACCESS_DENIED: - return "permission denied"; - break; - case PSI_ERR_LOCKED: - return "resource locked"; - break; - case PSI_ERR_WRITE: - return "write"; - break; - case PSI_ERR_DISMOUNTED: - return "dismounted"; - break; - case PSI_ERR_EoF: - return "end of file"; - break; - case PSI_ERR_DISK_FULL: - return "disk full"; - break; - case PSI_ERR_BAD_DRIVER: - return "bad driver"; - break; - case PSI_ERR_BAD_NAME: - return "bad name"; - break; - case PSI_ERR_COMMS_LINE_FAIL: - return "comms line failed"; - break; - case PSI_ERR_COMMS_FRAME: - return "comms framing error"; - break; - case PSI_ERR_COMMS_OVERRUN: - return "comms overrun"; - break; - case PSI_ERR_COMMS_PARITY: - return "comms parity error"; - break; - case PSI_ERR_TIMEOUT: - return "timed out"; - break; - case PSI_ERR_COULD_NOT_CONNECT: - return "could not connect"; - break; - case PSI_ERR_COULD_NOT_DISCONNECT: - return "could not disconnect"; - break; - case PSI_ERR_DISCONNECTED: - return "unit disconnected"; - break; - case PSI_ERR_BAD_LIBRARY_ENTRY_POINT: - return "bad library entry point"; - break; - case PSI_ERR_BAD_DESCRIPTOR: - return "bad descriptor"; - break; - case PSI_ERR_ABORT: - return "abort"; - break; - case PSI_ERR_TOO_BIG: - return "too big"; - break; - case PSI_ERR_DIVIDE_BY_ZERO: - return "division by zero"; - break; - case PSI_ERR_BAD_POWER: - return "bad power"; - break; - case PSI_ERR_DIR_FULL: - return "directory full"; - break; - default: - return "Unknown error"; - break; - } -} - long rfsv32:: -fread(long handle, char *buf, long len) +fread(long handle, unsigned char *buf, long len) { long res; long count = 0; @@ -634,9 +521,9 @@ fread(long handle, char *buf, long len) do { bufferStore a; a.addDWord(handle); - a.addDWord(((len-count) > 2000)?2000:(len-count)); + a.addDWord(((len-count) > RFSV_SENDLEN)?RFSV_SENDLEN:(len-count)); if (!sendCommand(READ_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; if ((res = getResponse(a)) != 0) return res; res = a.getLen(); @@ -650,20 +537,20 @@ fread(long handle, char *buf, long len) } long rfsv32:: -fwrite(long handle, char *buf, long len) +fwrite(long handle, unsigned char *buf, long len) { long res; long total = 0; long count; do { - count = ((len - total) > 2000)?2000:(len - total); + count = ((len - total) > RFSV_SENDLEN)?RFSV_SENDLEN:(len - total); bufferStore a; bufferStore tmp((unsigned char *)buf, count); a.addDWord(handle); a.addBuff(tmp); if (!sendCommand(WRITE_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; if ((res = getResponse(a)) != 0) return res; total += count; @@ -673,42 +560,48 @@ fwrite(long handle, char *buf, long len) } long rfsv32:: -copyFromPsion(const char *from, const char *to) +copyFromPsion(const char *from, const char *to, cpCallback_t cb) { long handle; long res; long len; - if ((res = fopen(PSI_OMODE_SHARE_READERS | PSI_OMODE_BINARY, from, handle)) != 0) + if ((res = fopen(EPOC_OMODE_SHARE_READERS | EPOC_OMODE_BINARY, from, handle)) != 0) return res; ofstream op(to); if (!op) { fclose(handle); return -1; } + unsigned char *buff = new unsigned char[RFSV_SENDLEN]; do { - char buf[2000]; - if ((len = fread(handle, buf, sizeof(buf))) > 0) - op.write(buf, len); + if ((len = fread(handle, buff, RFSV_SENDLEN)) > 0) + op.write(buff, len); + if (cb) { + if (!cb(len)) { + len = E_PSI_FILE_CANCEL; + break; + } + } } while (len > 0); - + delete[]buff; fclose(handle); op.close(); return len; } long rfsv32:: -copyToPsion(const char *from, const char *to) +copyToPsion(const char *from, const char *to, cpCallback_t cb) { long handle; long res; ifstream ip(from); if (!ip) - return PSI_ERR_NOT_FOUND; - res = fcreatefile(PSI_OMODE_BINARY | PSI_OMODE_SHARE_EXCLUSIVE | PSI_OMODE_READ_WRITE, to, handle); + return E_PSI_FILE_NXIST; + res = fcreatefile(EPOC_OMODE_BINARY | EPOC_OMODE_SHARE_EXCLUSIVE | EPOC_OMODE_READ_WRITE, to, handle); if (res != 0) { - res = freplacefile(PSI_OMODE_BINARY | PSI_OMODE_SHARE_EXCLUSIVE | PSI_OMODE_READ_WRITE, to, handle); + res = freplacefile(EPOC_OMODE_BINARY | EPOC_OMODE_SHARE_EXCLUSIVE | EPOC_OMODE_READ_WRITE, to, handle); if (res != 0) return res; } @@ -717,19 +610,33 @@ copyToPsion(const char *from, const char *to) while (ip && !ip.eof()) { ip.read(buff, RFSV_SENDLEN); bufferStore tmp(buff, ip.gcount()); - total += tmp.getLen(); - if (tmp.getLen() == 0) + int len = tmp.getLen(); + total += len; + if (len == 0) break; bufferStore a; a.addDWord(handle); a.addBuff(tmp); - if (!sendCommand(WRITE_FILE, a)) - return PSI_ERR_DISCONNECTED; + if (!sendCommand(WRITE_FILE, a)) { + ip.close(); + delete[]buff; + return E_PSI_FILE_DISC; + } 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(); @@ -744,7 +651,7 @@ fsetsize(long handle, long size) a.addDWord(handle); a.addDWord(size); if (!sendCommand(SET_SIZE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; return getResponse(a); } @@ -776,7 +683,7 @@ fseek(long handle, long pos, long mode) */ if ((mode < PSI_SEEK_SET) || (mode > PSI_SEEK_END)) - return PSI_ERR_ARGUMENT; + return E_PSI_GEN_ARG; if ((mode == PSI_SEEK_CUR) && (pos >= 0)) { /* get and save current position */ @@ -784,7 +691,7 @@ fseek(long handle, long pos, long mode) a.addDWord(handle); a.addDWord(PSI_SEEK_CUR); if (!sendCommand(SEEK_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; if ((res = getResponse(a)) != 0) return res; savpos = a.getDWord(0); @@ -798,7 +705,7 @@ fseek(long handle, long pos, long mode) a.addDWord(handle); a.addDWord(PSI_SEEK_END); if (!sendCommand(SEEK_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; if ((res = getResponse(a)) != 0) return res; savpos = a.getDWord(0); @@ -809,7 +716,7 @@ fseek(long handle, long pos, long mode) a.addDWord(handle); a.addDWord(savpos + pos); if (!sendCommand(SET_SIZE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; if ((res = getResponse(a)) != 0) return res; pos = 0; @@ -820,7 +727,7 @@ fseek(long handle, long pos, long mode) a.addDWord(handle); a.addDWord(mode); if (!sendCommand(SEEK_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; if ((res = getResponse(a)) != 0) return res; realpos = a.getDWord(0); @@ -841,14 +748,14 @@ fseek(long handle, long pos, long mode) a.addDWord(handle); a.addDWord(calcpos); if (!sendCommand(SET_SIZE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; if ((res = getResponse(a)) != 0) return res; a.addDWord(calcpos); a.addDWord(handle); a.addDWord(PSI_SEEK_SET); if (!sendCommand(SEEK_FILE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; if ((res = getResponse(a)) != 0) return res; realpos = a.getDWord(0); @@ -871,7 +778,7 @@ mkdir(const char *name) } free(n); if (!sendCommand(MK_DIR_ALL, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; return getResponse(a); } @@ -890,7 +797,7 @@ rmdir(const char *name) } free(n); if (!sendCommand(RM_DIR, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; return getResponse(a); } @@ -907,7 +814,7 @@ rename(const char *oldname, const char *newname) free(on); free(nn); if (!sendCommand(RENAME, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; return getResponse(a); } @@ -920,6 +827,63 @@ remove(const char *name) a.addString(n); free(n); if (!sendCommand(DELETE, a)) - return PSI_ERR_DISCONNECTED; + return E_PSI_FILE_DISC; return getResponse(a); } + +static long e2psi[] = { + rfsv::E_PSI_FILE_DIRFULL, // -43 + rfsv::E_PSI_GEN_POWER, // -42 + rfsv::E_PSI_GEN_DIVIDE, // -41 + rfsv::E_PSI_FILE_TOOBIG, // -40 + rfsv::E_PSI_FILE_ABORT, // -39 + rfsv::E_PSI_GEN_DESCR, // -38 + rfsv::E_PSI_GEN_LIB, // -37 + rfsv::E_PSI_FILE_NDISC, // -36 + rfsv::E_PSI_FILE_DISC, // -35 + rfsv::E_PSI_FILE_CONNECT, // -34 + rfsv::E_PSI_FILE_RETRAN, // -33 + rfsv::E_PSI_FILE_PARITY, // -32 + rfsv::E_PSI_FILE_OVERRUN, // -31 + rfsv::E_PSI_FILE_FRAME, // -30 + rfsv::E_PSI_FILE_LINE, // -29 + rfsv::E_PSI_FILE_NAME, // -28 + rfsv::E_PSI_FILE_DRIVER, // -27 + rfsv::E_PSI_FILE_FULL, // -26 + rfsv::E_PSI_FILE_EOF, // -25 + rfsv::E_PSI_GEN_FSYS, // -24 + rfsv::E_PSI_FILE_WRITE, // -23 + rfsv::E_PSI_FILE_LOCKED, // -22 + rfsv::E_PSI_FILE_ACCESS, // -21 + rfsv::E_PSI_FILE_CORRUPT, // -20 + rfsv::E_PSI_FILE_UNKNOWN, // -19 + rfsv::E_PSI_FILE_NOTREADY, // -18 + rfsv::E_PSI_FILE_COMPLETION, // -17 + rfsv::E_PSI_GEN_BUSY, // -16 + rfsv::E_PSI_GEN_TERMINATED, // -15 + rfsv::E_PSI_GEN_INUSE, // -14 + rfsv::E_PSI_GEN_DIED, // -13 + rfsv::E_PSI_FILE_DIR, // -12 + rfsv::E_PSI_FILE_EXIST, // -11 + rfsv::E_PSI_GEN_UNDER, // -10 + rfsv::E_PSI_GEN_OVER, // -9 + rfsv::E_PSI_FILE_HANDLE, // -8 + rfsv::E_PSI_GEN_RANGE, // -7 + rfsv::E_PSI_GEN_ARG, // -6 + rfsv::E_PSI_GEN_NSUP, // -5 + rfsv::E_PSI_GEN_NOMEMORY, // -4 + rfsv::E_PSI_FILE_CANCEL, // -3 + rfsv::E_PSI_GEN_FAIL, // -2 + rfsv::E_PSI_FILE_NXIST, // -1 + rfsv::E_PSI_GEN_NONE // 0 +}; + +long rfsv32:: +err2psierr(long status) +{ + if ((status > E_EPOC_NONE) || (status < E_EPOC_DIR_FULL)) { + cerr << "FATAL: inavlid error-code" << endl; + return -999; + } + return e2psi[status - E_EPOC_DIR_FULL]; +} diff --git a/lib/rfsv32.h b/lib/rfsv32.h index 00cab2b..8383e72 100644 --- a/lib/rfsv32.h +++ b/lib/rfsv32.h @@ -1,121 +1,119 @@ #ifndef _rfsv32_h_ #define _rfsv32_h_ +#include "rfsv.h" + class ppsocket; class bufferStore; class bufferArray; -class rfsv32 { +class rfsv32 : public rfsv { public: - rfsv32(ppsocket * skt); + rfsv32(ppsocket *); ~rfsv32(); void reset(); void reconnect(); - long dir(const char *name, bufferArray * files); - long dircount(const char *name, long *count); - long copyFromPsion(const char *from, const char *to); - long copyToPsion(const char *from, const char *to); - long mkdir(const char *name); - long rmdir(const char *name); - long remove(const char *name); - long rename(const char *oldname, const char *newname); - long mktemp(long *handle, char *tmpname); - long fgeteattr(const char *name, long *attr, long *size, long *time); - long fgetattr(const char *name, long *attr); - long fsetattr(const char *name, long seta, long unseta); - long fgetmtime(const char *name, long *mtime); - long fsetmtime(const char *name, long mtime); - long fopendir(long attr, const char *name, long &handle); - long fopen(long attr, const char *name, long &handle); - long fcreatefile(long attr, const char *name, long &handle); - long freplacefile(long attr, const char *name, long &handle); - long fseek(long handle, long pos, long mode); - long fread(long handle, char *buf, long len); - long fwrite(long handle, char *buf, long len); - long fsetsize(long handle, long size); - long fclose(long handle); + long dir(const char *, bufferArray *); + long dircount(const char *, long *); + long copyFromPsion(const char *, const char *, cpCallback_t); + long copyToPsion(const char *, const char *, cpCallback_t); + long mkdir(const char *); + long rmdir(const char *); + long remove(const char *); + long rename(const char *, const char *); + long mktemp(long *, char *); + long fgeteattr(const char *, long *, long *, long *); + long fgetattr(const char *, long *); + long fsetattr(const char *, long, long); + long fgetmtime(const char *, long *); + long fsetmtime(const char *, long); + long fopendir(long, const char *, long &); + long fopen(long, const char *, long &); + long fcreatefile(long, const char *, long &); + long freplacefile(long, const char *, long &); + long fseek(long, long, long); + long fread(long, unsigned char *, long); + long fwrite(long, unsigned char *, long); + long fsetsize(long, long); + long fclose(long); - long devlist(long *devbits); - char *devinfo(int devnum, long *vfree, long *vtotal, long *vattr, long *vuiqueid); + long devlist(long *); + char *devinfo(int, long *, long *, long *, long *); long getStatus(); - char *opErr(long status); - - enum seek_mode { - PSI_SEEK_SET = 1, - PSI_SEEK_CUR = 2, - PSI_SEEK_END = 3 - }; + char *opAttr(long); + long opMode(long); + private: + enum file_attrib { - PSI_ATTR_RONLY = 0x0001, - PSI_ATTR_HIDDEN = 0x0002, - PSI_ATTR_SYSTEM = 0x0004, - PSI_ATTR_DIRECTORY = 0x0010, - PSI_ATTR_ARCHIVE = 0x0020, - PSI_ATTR_VOLUME = 0x0040, - PSI_ATTR_NORMAL = 0x0080, - PSI_ATTR_TEMPORARY = 0x0100, - PSI_ATTR_COMPRESSED = 0x0800 + EPOC_ATTR_RONLY = 0x0001, + EPOC_ATTR_HIDDEN = 0x0002, + EPOC_ATTR_SYSTEM = 0x0004, + EPOC_ATTR_DIRECTORY = 0x0010, + EPOC_ATTR_ARCHIVE = 0x0020, + EPOC_ATTR_VOLUME = 0x0040, + EPOC_ATTR_NORMAL = 0x0080, + EPOC_ATTR_TEMPORARY = 0x0100, + EPOC_ATTR_COMPRESSED = 0x0800 }; enum open_mode { - PSI_OMODE_SHARE_EXCLUSIVE = 0x0000, - PSI_OMODE_SHARE_READERS = 0x0001, - PSI_OMODE_SHARE_ANY = 0x0002, - PSI_OMODE_BINARY = 0x0000, - PSI_OMODE_TEXT = 0x0020, - PSI_OMODE_READ_WRITE = 0x0200 + EPOC_OMODE_SHARE_EXCLUSIVE = 0x0000, + EPOC_OMODE_SHARE_READERS = 0x0001, + EPOC_OMODE_SHARE_ANY = 0x0002, + EPOC_OMODE_BINARY = 0x0000, + EPOC_OMODE_TEXT = 0x0020, + EPOC_OMODE_READ_WRITE = 0x0200 }; - enum errs { - PSI_ERR_NONE = 0, - PSI_ERR_NOT_FOUND = -1, - PSI_ERR_GENERAL = -2, - PSI_ERR_CANCEL = -3, - PSI_ERR_NO_MEMORY = -4, - PSI_ERR_NOT_SUPPORTED = -5, - PSI_ERR_ARGUMENT = -6, - PSI_ERR_TOTAL_LOSS_OF_PRECISION = -7, - PSI_ERR_BAD_HANDLE = -8, - PSI_ERR_OVERFLOW = -9, - PSI_ERR_UNDERFLOW = -10, - PSI_ERR_ALREADY_EXISTS = -11, - PSI_ERR_PATH_NOT_FOUND = -12, - PSI_ERR_DIED = -13, - PSI_ERR_IN_USE = -14, - PSI_ERR_SERVER_TERMINATED = -15, - PSI_ERR_SERVER_BUSY = -16, - PSI_ERR_COMPLETION = -17, - PSI_ERR_NOT_READY = -18, - PSI_ERR_UNKNOWN = -19, - PSI_ERR_CORRUPT = -20, - PSI_ERR_ACCESS_DENIED = -21, - PSI_ERR_LOCKED = -22, - PSI_ERR_WRITE = -23, - PSI_ERR_DISMOUNTED = -24, - PSI_ERR_EoF = -25, - PSI_ERR_DISK_FULL = -26, - PSI_ERR_BAD_DRIVER = -27, - PSI_ERR_BAD_NAME = -28, - PSI_ERR_COMMS_LINE_FAIL = -29, - PSI_ERR_COMMS_FRAME = -30, - PSI_ERR_COMMS_OVERRUN = -31, - PSI_ERR_COMMS_PARITY = -32, - PSI_ERR_TIMEOUT = -33, - PSI_ERR_COULD_NOT_CONNECT = -34, - PSI_ERR_COULD_NOT_DISCONNECT = -35, - PSI_ERR_DISCONNECTED = -36, - PSI_ERR_BAD_LIBRARY_ENTRY_POINT = -37, - PSI_ERR_BAD_DESCRIPTOR = -38, - PSI_ERR_ABORT = -39, - PSI_ERR_TOO_BIG = -40, - PSI_ERR_DIVIDE_BY_ZERO = -41, - PSI_ERR_BAD_POWER = -42, - PSI_ERR_DIR_FULL = -43 + enum epoc_errs { + E_EPOC_NONE = 0, + E_EPOC_NOT_FOUND = -1, + E_EPOC_GENERAL = -2, + E_EPOC_CANCEL = -3, + E_EPOC_NO_MEMORY = -4, + E_EPOC_NOT_SUPPORTED = -5, + E_EPOC_ARGUMENT = -6, + E_EPOC_TOTAL_LOSS_OF_PRECISION = -7, + E_EPOC_BAD_HANDLE = -8, + E_EPOC_OVERFLOW = -9, + E_EPOC_UNDERFLOW = -10, + E_EPOC_ALREADY_EXISTS = -11, + E_EPOC_PATH_NOT_FOUND = -12, + E_EPOC_DIED = -13, + E_EPOC_IN_USE = -14, + E_EPOC_SERVER_TERMINATED = -15, + E_EPOC_SERVER_BUSY = -16, + E_EPOC_COMPLETION = -17, + E_EPOC_NOT_READY = -18, + E_EPOC_UNKNOWN = -19, + E_EPOC_CORRUPT = -20, + E_EPOC_ACCESS_DENIED = -21, + E_EPOC_LOCKED = -22, + E_EPOC_WRITE = -23, + E_EPOC_DISMOUNTED = -24, + E_EPOC_EoF = -25, + E_EPOC_DISK_FULL = -26, + E_EPOC_BAD_DRIVER = -27, + E_EPOC_BAD_NAME = -28, + E_EPOC_COMMS_LINE_FAIL = -29, + E_EPOC_COMMS_FRAME = -30, + E_EPOC_COMMS_OVERRUN = -31, + E_EPOC_COMMS_PARITY = -32, + E_EPOC_TIMEOUT = -33, + E_EPOC_COULD_NOT_CONNECT = -34, + E_EPOC_COULD_NOT_DISCONNECT = -35, + E_EPOC_DISCONNECTED = -36, + E_EPOC_BAD_LIBRARY_ENTRY_POINT = -37, + E_EPOC_BAD_DESCRIPTOR = -38, + E_EPOC_ABORT = -39, + E_EPOC_TOO_BIG = -40, + E_EPOC_DIVIDE_BY_ZERO = -41, + E_EPOC_BAD_POWER = -42, + E_EPOC_DIR_FULL = -43 }; - private: enum commands { CLOSE_HANDLE = 0x01, OPEN_DIR = 0x10, @@ -154,15 +152,16 @@ class rfsv32 { }; const char *getConnectName(); + long err2psierr(long); // Communication - bool sendCommand(enum commands c, bufferStore & data); - long getResponse(bufferStore & data); - char *convertSlash(const char *name); + bool sendCommand(enum commands, bufferStore &); + long getResponse(bufferStore &); + char *convertSlash(const char *); // time-conversion - unsigned long micro2time(unsigned long microHi, unsigned long microLo); - void time2micro(unsigned long mtime, unsigned long µHi, unsigned long µLo); + unsigned long micro2time(unsigned long, unsigned long); + void time2micro(unsigned long, unsigned long &, unsigned long &); // Vars ppsocket *skt; diff --git a/lib/rfsvfactory.cc b/lib/rfsvfactory.cc new file mode 100644 index 0000000..2e2067e --- /dev/null +++ b/lib/rfsvfactory.cc @@ -0,0 +1,86 @@ +// +// RFSVFACTORY - factory object that creates an appropriate RFSV object +// based on whatever the NCP daemon discovered in the INFO exchange. +// +// Copyright (C) 1999 Matt J. Gumbley <matt@gumbley.demon.co.uk> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#include <stream.h> +#include <stdlib.h> +#include <fstream.h> +#include <iomanip.h> +#include <time.h> +#include <string.h> + +#include "defs.h" +#include "bool.h" +#include "rfsv.h" +#include "rfsv16.h" +#include "rfsv32.h" +#include "rfsvfactory.h" +#include "bufferstore.h" +#include "ppsocket.h" +#include "bufferarray.h" + +rfsvfactory::rfsvfactory(ppsocket *_skt) : serNum(0) +{ + skt = _skt; +} + +rfsv * rfsvfactory::create(bool reconnect) +{ + // skt is connected to the ncp daemon, which will have (hopefully) seen + // an INFO exchange, where the protocol version of the remote Psion was + // sent, and noted. We have to ask the ncp daemon which protocol it saw, + // so we can instantiate the correct RFSV protocol handler for the + // caller. We announce ourselves to the NCP daemon, and the relevant + // RFSV module will also announce itself. + bufferStore a; + a.init(); + a.addStringT("NCP$INFO"); + if (!skt->sendBufferStore(a)) { + if (!reconnect) + cerr << "rfsvfactory::create couldn't send version request" << endl; else { + skt->closeSocket(); + serNum = 0; + skt->reconnect(); + } + return NULL; + } + if (skt->getBufferStore(a) == 1) { + if (a.getLen() > 8 && !strncmp(a.getString(), "Series 3", 8)) { + return new rfsv16(skt); + } + else if (a.getLen() > 8 && !strncmp(a.getString(), "Series 5", 8)) { + return new rfsv32(skt); + } + if ((a.getLen() > 8) && !strncmp(a.getString(), "No Psion", 8)) { + skt->closeSocket(); + serNum = 0; + skt->reconnect(); + return NULL; + } + // Invalid protocol version + cerr << "rfsvfactory::create received odd protocol version from +ncpd! (" << a << ")" << endl; + } else { + cerr << "rfsvfactory::create sent, response not 1" << endl; + } + + // No message returned. + return NULL; +} + diff --git a/lib/rfsvfactory.h b/lib/rfsvfactory.h new file mode 100644 index 0000000..17b7252 --- /dev/null +++ b/lib/rfsvfactory.h @@ -0,0 +1,20 @@ +#ifndef _rfsvfactory_h_ +#define _rfsvfactory_h_ + +#include "rfsv.h" + +class ppsocket; + +class rfsvfactory { + public: + rfsvfactory(ppsocket * skt); + virtual rfsv * create(bool); + + private: + // Vars + ppsocket *skt; + int serNum; +}; + +#endif + diff --git a/lib/rpcs.cc b/lib/rpcs.cc new file mode 100644 index 0000000..5863c5b --- /dev/null +++ b/lib/rpcs.cc @@ -0,0 +1,283 @@ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include <stream.h> +#include <stdlib.h> +#include <fstream.h> +#include <iomanip.h> +#include <time.h> +#include <string.h> + +#include "defs.h" +#include "bool.h" +#include "rpcs.h" +#include "bufferstore.h" +#include "ppsocket.h" +#include "bufferarray.h" + +// +// public common API +// +void rpcs:: +reconnect() +{ + skt->closeSocket(); + skt->reconnect(); + reset(); +} + +void rpcs:: +reset() +{ + bufferStore a; + status = E_PSI_FILE_DISC; + a.addStringT(getConnectName()); + if (skt->sendBufferStore(a)) { + if (skt->getBufferStore(a) == 1) { + if (!strcmp(a.getString(0), "Ok")) + status = E_PSI_GEN_NONE; + } + } +} + +long rpcs:: +getStatus() +{ + return status; +} + +const char *rpcs:: +getConnectName() +{ + return "SYS$RPCS"; +} + +// +// 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) +{ + if (status == E_PSI_FILE_DISC) { + reconnect(); + if (status == E_PSI_FILE_DISC) + return false; + } + bool result; + bufferStore a; + a.addByte(cc); + a.addBuff(data); + result = skt->sendBufferStore(a); + if (!result) + status = E_PSI_FILE_DISC; + return result; +} + +long rpcs:: +getResponse(bufferStore & data) +{ + if (skt->getBufferStore(data) == 1) { + long ret = data.getByte(0); + return ret; + } else + status = E_PSI_FILE_DISC; + return status; +} + +// +// APIs, identical on SIBO and EPOC +// +int rpcs:: +getNCPversion(int &major, int &minor) +{ + bufferStore a; + if (!sendCommand(QUERY_NCP, a)) + return E_PSI_FILE_DISC; + long res = getResponse(a); + a.discardFirstBytes(1); + if (res) + return res; + if (a.getLen() != 2) + return E_PSI_GEN_FAIL; + major = a.getByte(0); + minor = a.getByte(1); + return res; +} + +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--) + a.addByte(0); + a.addByte(strlen(args)); + a.addStringT(args); + if (!sendCommand(EXEC_PROG, a)) + return E_PSI_FILE_DISC; + long res = getResponse(a); +cout << res << " " << a << endl; + return res; +} + +int rpcs:: +stopProgram(const char *program) +{ + bufferStore a; + a.addStringT(program); + if (!sendCommand(STOP_PROG, a)) + return E_PSI_FILE_DISC; + return getResponse(a); +} + +int rpcs:: +queryProgram(const char *program) +{ + bufferStore a; + a.addStringT(program); + if (!sendCommand(QUERY_PROG, a)) + return E_PSI_FILE_DISC; + return getResponse(a); +} + +int rpcs:: +formatOpen(const char *drive, int &handle, int &count) +{ + bufferStore a; + a.addStringT(drive); + if (!sendCommand(FORMAT_OPEN, a)) + return E_PSI_FILE_DISC; + long res = getResponse(a); + a.discardFirstBytes(1); + if (res) + return res; + if (a.getLen() != 4) + return E_PSI_GEN_FAIL; + handle = a.getWord(0); + count = a.getWord(2); + return res; +} + +int rpcs:: +formatRead(int handle) +{ + bufferStore a; + a.addWord(handle); + if (!sendCommand(FORMAT_READ, a)) + return E_PSI_FILE_DISC; + return getResponse(a); +} + +int rpcs:: +getUniqueID(const char *device, long &id) +{ + bufferStore a; + a.addStringT(device); + if (!sendCommand(GET_UNIQUEID, a)) + return E_PSI_FILE_DISC; + long res = getResponse(a); + a.discardFirstBytes(1); + if (res) + return res; + if (a.getLen() != 4) + return E_PSI_GEN_FAIL; + id = a.getDWord(0); + return res; +} + +int rpcs:: +getOwnerInfo(bufferArray &ret) +{ + bufferStore a; + if (!sendCommand(GET_OWNERINFO, a)) + return E_PSI_FILE_DISC; + long res = getResponse(a); + a.discardFirstBytes(1); + if (res) + return res; + a.addByte(0); + int l = a.getLen(); + char *s = (char *)a.getString(0); + for (int i = 0; i < l; i++) + if (s[i] == 6) + s[i] = 0; + ret.clear(); + while (l > 0) { + bufferStore b; + b.addStringT(s); + ret += b; + l -= (strlen(s) + 1); + s += (strlen(s) + 1); + } + return res; +} + +int rpcs:: +getMachineType(int &type) +{ + bufferStore a; + if (!sendCommand(GET_MACHINETYPE, a)) + return E_PSI_FILE_DISC; + long res = getResponse(a); + a.discardFirstBytes(1); + if (res) + return res; + if (a.getLen() != 2) + return E_PSI_GEN_FAIL; + type = a.getWord(0); + return res; +} + +int rpcs:: +fuser(const char *name, char *buf, int bufsize) +{ + bufferStore a; + a.addStringT(name); + if (!sendCommand(FUSER, a)) + return E_PSI_FILE_DISC; + long res = getResponse(a); + a.discardFirstBytes(1); + if (res) + return res; + int len = ((int)a.getLen() > bufsize) ? bufsize - 1 : a.getLen(); + strncpy(buf, a.getString(0), len); + buf[len] = '\0'; + char *p; + while ((p = strchr(buf, 6))) + *p = '\n'; + return res; +} + +int rpcs:: +quitServer() +{ + bufferStore a; + if (!sendCommand(QUIT_SERVER, a)) + return E_PSI_FILE_DISC; + return getResponse(a); +} + diff --git a/lib/rpcs.h b/lib/rpcs.h new file mode 100644 index 0000000..cb71c88 --- /dev/null +++ b/lib/rpcs.h @@ -0,0 +1,103 @@ +#ifndef _rpcs_h_ +#define _rpcs_h_ + +class ppsocket; +class bufferStore; +class bufferArray; + +class rpcs { + public: + virtual ~rpcs() {}; + void reset(); + void reconnect(); + long getStatus(); + + // API idendical on SIBO and EPOC + int getNCPversion(int &, int &); + int execProgram(const char *, const char *); + int stopProgram(const char *); + int queryProgram(const char *); + int formatOpen(const char *, int &, int &); + int formatRead(int); + int getUniqueID(const char *, long &); + int getOwnerInfo(bufferArray &); + int getMachineType(int &); + int fuser(const char *, char *, int); + int quitServer(void); + + // API different on SIBO and EPOC + virtual int queryDrive(const char, bufferArray &) = 0; + virtual int getCmdLine(const char *, char *, int) = 0; + + // API only existent on EPOC + // default-methods for SIBO here. + virtual int getMachineInfo(void) { 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;} + virtual int regWrite(void) { return E_PSI_NOT_SIBO;} + virtual int regRead(void) { return E_PSI_NOT_SIBO;} + virtual int regDelete(void) { return E_PSI_NOT_SIBO;} + virtual int setTime(void) { return E_PSI_NOT_SIBO;} + virtual int configOpen(void) { return E_PSI_NOT_SIBO;} + virtual int configRead(void) { return E_PSI_NOT_SIBO;} + virtual int configWrite(void) { return E_PSI_NOT_SIBO;} + virtual int queryOpen(void) { return E_PSI_NOT_SIBO;} + virtual int queryRead(void) { return E_PSI_NOT_SIBO;} + + enum errs { + E_PSI_GEN_NONE = 0, + E_PSI_GEN_FAIL = -1, + E_PSI_FILE_DISC = -50, + // Special error code for "Operation not permitted in RPCS16" + E_PSI_NOT_SIBO = -200 + }; + + enum machs { + PSI_MACH_UNKNOWN = 0, + PSI_MACH_PC = 1, + PSI_MACH_MC = 2, + PSI_MACH_HC = 3, + PSI_MACH_S3 = 4, + PSI_MACH_S3A = 5, + PSI_MACH_WORKABOUT = 6, + PSI_MACH_SIENNA = 7, + PSI_MACH_S3C = 8, + PSI_MACH_S5 = 32, + PSI_MACH_WINC = 33, +//TODO: Code for 5mx + }; + + protected: + + // Vars + ppsocket *skt; + long status; + + enum commands { + QUERY_NCP = 0x00, + EXEC_PROG = 0x01, + QUERY_DRIVE = 0x02, + STOP_PROG = 0x03, + QUERY_PROG = 0x04, + FORMAT_OPEN = 0x05, + FORMAT_READ = 0x06, + GET_UNIQUEID = 0x07, + GET_OWNERINFO = 0x08, + GET_MACHINETYPE = 0x09, + GET_CMDLINE = 0x0a, + FUSER = 0x0b, + CONFIG_OPEN = 0x66, + CONFIG_READ = 0x6d, + QUIT_SERVER = 0xff + }; + + // Communication + bool sendCommand(enum commands, bufferStore &); + long getResponse(bufferStore &); + const char *getConnectName(); + + char *convertSlash(const char *); +}; + +#endif diff --git a/lib/rpcs16.cc b/lib/rpcs16.cc new file mode 100644 index 0000000..2786ee8 --- /dev/null +++ b/lib/rpcs16.cc @@ -0,0 +1,63 @@ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include <stream.h> +#include <stdlib.h> +#include <fstream.h> +#include <iomanip.h> +#include <time.h> +#include <string.h> + +#include "defs.h" +#include "bool.h" +#include "rpcs16.h" +#include "bufferstore.h" +#include "ppsocket.h" + +rpcs16::rpcs16(ppsocket * _skt) +{ + skt = _skt; + reset(); +} + +rpcs16::~rpcs16() +{ + bufferStore a; + a.addStringT("Close"); + if (status == E_PSI_GEN_NONE) + skt->sendBufferStore(a); + skt->closeSocket(); +} + +int rpcs16:: +queryDrive(char drive, bufferArray &ret) +{ + bufferStore a; + a.addByte(drive); + if (!sendCommand(rpcs::QUERY_DRIVE, a)) + return rpcs::E_PSI_FILE_DISC; + long res = getResponse(a); +cout << dec << "qd: " << res << " " << a.getLen() << " a="<< a << endl; + if (res) + return res; + return res; +} + +int rpcs16:: +getCmdLine(const char *process, char *buf, int bufsize) +{ + return 0; +} diff --git a/lib/rpcs16.h b/lib/rpcs16.h new file mode 100644 index 0000000..14809ae --- /dev/null +++ b/lib/rpcs16.h @@ -0,0 +1,18 @@ +#ifndef _rpcs16_h_ +#define _rpcs16_h_ + +#include "rpcs.h" + +class ppsocket; +class bufferStore; + +class rpcs16 : public rpcs { + public: + rpcs16(ppsocket *); + ~rpcs16(); + + int queryDrive(const char, bufferArray &); + int getCmdLine(const char *, char *, int); +}; + +#endif diff --git a/lib/rpcs32.cc b/lib/rpcs32.cc new file mode 100644 index 0000000..d710b9c --- /dev/null +++ b/lib/rpcs32.cc @@ -0,0 +1,114 @@ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include <stream.h> +#include <stdio.h> +#include <stdlib.h> +#include <fstream.h> +#include <iomanip.h> +#include <time.h> +#include <string.h> + +#include "defs.h" +#include "bool.h" +#include "rpcs32.h" +#include "bufferstore.h" +#include "bufferarray.h" +#include "ppsocket.h" + +rpcs32::rpcs32(ppsocket * _skt) +{ + skt = _skt; + reset(); +} + +rpcs32::~rpcs32() +{ + bufferStore a; + a.addStringT("Close"); + if (status == E_PSI_GEN_NONE) + skt->sendBufferStore(a); + skt->closeSocket(); +} + +int rpcs32:: +queryDrive(char drive, bufferArray &ret) +{ + bufferStore a; + a.addByte(drive); + if (!sendCommand(rpcs::QUERY_DRIVE, a)) + return rpcs::E_PSI_FILE_DISC; + getResponse(a); + int l = a.getLen(); + ret.clear(); +//cout << dec << "qd: " << a.getLen() << " a="<< a << endl; + while (l > 1) { + bufferStore b, c; + const char *s; + char *p; + int pid; + int sl; + + s = a.getString(0); + sl = strlen(s) + 1; + l -= sl; + a.discardFirstBytes(sl); + p = strstr(s, ".$"); + if (p) { + *p = '\0'; p += 2; + sscanf(p, "%d", &pid); + } else + pid = 0; + b.addWord(pid); + b.addStringT(s); + s = a.getString(0); + sl = strlen(s) + 1; + l -= sl; + a.discardFirstBytes(sl); + c.addStringT(s); + ret.push(c); + ret.push(b); + } + return 0; +} + +int rpcs32:: +getCmdLine(const char *process, char *buf, int bufsize) +{ + return 0; +} + +int rpcs32:: +configOpen(void) +{ + bufferStore a; +cout << "configOpen:" << endl; + if (!sendCommand(rpcs::CONFIG_OPEN, a)) + return rpcs::E_PSI_FILE_DISC; + getResponse(a); +cout << a << endl; +} + +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; +} diff --git a/lib/rpcs32.h b/lib/rpcs32.h new file mode 100644 index 0000000..e33ef10 --- /dev/null +++ b/lib/rpcs32.h @@ -0,0 +1,36 @@ +#ifndef _rpcs32_h_ +#define _rpcs32_h_ + +#include "rpcs.h" + +class ppsocket; + +class rpcs32 : public rpcs { + public: + rpcs32(ppsocket *); + ~rpcs32(); + + int queryDrive(const char, bufferArray &); + int getCmdLine(const char *, char *, int); +#if 0 + int getMachineInfo(void); + int closeHandle(int); + int regOpenIter(void); + int regReadIter(void); + int regWrite(void); + 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); + int quitServer(void); +#endif + +}; + +#endif diff --git a/lib/rpcsfactory.cc b/lib/rpcsfactory.cc new file mode 100644 index 0000000..7358e56 --- /dev/null +++ b/lib/rpcsfactory.cc @@ -0,0 +1,85 @@ +// +// RPCSFACTORY - factory object that creates an appropriate RPCS object +// based on whatever the NCP daemon discovered in the INFO exchange. +// Derived from rfsvfactory by Matt J. Gumbley <matt@gumbley.demon.co.uk> +// +// Copyright (C) 2000 Fritz Elfert <felfert@to.com> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#include <stream.h> +#include <stdlib.h> +#include <fstream.h> +#include <iomanip.h> +#include <time.h> +#include <string.h> + +#include "defs.h" +#include "bool.h" +#include "rpcs16.h" +#include "rpcs32.h" +#include "rpcsfactory.h" +#include "bufferstore.h" +#include "ppsocket.h" + +rpcsfactory::rpcsfactory(ppsocket *_skt) : serNum(0) +{ + skt = _skt; +} + +rpcs * rpcsfactory::create(bool reconnect) +{ + // skt is connected to the ncp daemon, which will have (hopefully) seen + // an INFO exchange, where the protocol version of the remote Psion was + // sent, and noted. We have to ask the ncp daemon which protocol it saw, + // so we can instantiate the correct rpcs protocol handler for the + // caller. We announce ourselves to the NCP daemon, and the relevant + // rpcs module will also announce itself. + bufferStore a; + a.init(); + a.addStringT("NCP$INFO"); + if (!skt->sendBufferStore(a)) { + if (!reconnect) + cerr << "rpcsfactory::create couldn't send version request" << endl; else { + skt->closeSocket(); + serNum = 0; + skt->reconnect(); + } + return NULL; + } + if (skt->getBufferStore(a) == 1) { + if (a.getLen() > 8 && !strncmp(a.getString(), "Series 3", 8)) { + return new rpcs16(skt); + } + else if (a.getLen() > 8 && !strncmp(a.getString(), "Series 5", 8)) { + return new rpcs32(skt); + } + if ((a.getLen() > 8) && !strncmp(a.getString(), "No Psion", 8)) { + skt->closeSocket(); + serNum = 0; + skt->reconnect(); + return NULL; + } + // Invalid protocol version + cerr << "rpcsfactory::create received odd protocol version from +ncpd! (" << a << ")" << endl; + } else { + cerr << "rpcsfactory::create sent, response not 1" << endl; + } + + // No message returned. + return NULL; +} + diff --git a/lib/rpcsfactory.h b/lib/rpcsfactory.h new file mode 100644 index 0000000..17a2719 --- /dev/null +++ b/lib/rpcsfactory.h @@ -0,0 +1,20 @@ +#ifndef _rpcsfactory_h_ +#define _rpcsfactory_h_ + +#include "rpcs.h" + +class ppsocket; + +class rpcsfactory { + public: + rpcsfactory(ppsocket * skt); + virtual rpcs * create(bool); + + private: + // Vars + ppsocket *skt; + int serNum; +}; + +#endif + diff --git a/ncpd/channel.cc b/ncpd/channel.cc index a75c791..f52cea1 100644 --- a/ncpd/channel.cc +++ b/ncpd/channel.cc @@ -32,6 +32,7 @@ channel::channel(ncp * _ncpController) { verbose = 0; + ncpChannel = 0; ncpController = _ncpController; _terminate = false; } @@ -61,17 +62,41 @@ ncpConnect() } void channel:: +ncpRegister() +{ + ncpController->Register(this); +} + +void channel:: +ncpDoRegisterAck(int ch) +{ + ncpController->RegisterAck(ch); +} + +void channel:: ncpDisconnect() { ncpController->disconnect(ncpChannel); } +short int channel:: +ncpProtocolVersion() +{ + return ncpController->getProtocolVersion(); +} + void channel:: setNcpChannel(int chan) { ncpChannel = chan; } +int channel:: +getNcpChannel() +{ + return ncpChannel; +} + void channel:: newNcpController(ncp * _ncpController) { diff --git a/ncpd/channel.h b/ncpd/channel.h index a8f5225..2c06d6d 100644 --- a/ncpd/channel.h +++ b/ncpd/channel.h @@ -35,18 +35,25 @@ class bufferStore; class channel { public: channel(ncp *ncpController); + virtual ~channel() {} void newNcpController(ncp *ncpController); void setNcpChannel(int chan); + int getNcpChannel(void); void ncpSend(bufferStore &a); void setVerbose(short int _verbose); short int getVerbose(); virtual void ncpDataCallback(bufferStore &a) = NULL; - virtual const char *getNcpConnectName() = NULL; + virtual char *getNcpConnectName() = NULL; void ncpConnect(); + void ncpRegister(); + void ncpDoRegisterAck(int); virtual void ncpConnectAck() = NULL; virtual void ncpConnectTerminate() = NULL; + virtual void ncpConnectNak() = NULL; + virtual void ncpRegisterAck() = NULL; void ncpDisconnect(); + short int ncpProtocolVersion(); // The following two calls are used for destructing an instance virtual bool terminate(); // Mainloop will terminate this class if true @@ -57,8 +64,8 @@ class channel { private: ncp *ncpController; - bool _terminate; int ncpChannel; + bool _terminate; }; #endif diff --git a/ncpd/linkchan.cc b/ncpd/linkchan.cc index e4891c1..4a2a4d4 100644 --- a/ncpd/linkchan.cc +++ b/ncpd/linkchan.cc @@ -23,30 +23,63 @@ // e-mail philip.proudman@btinternet.com #include <stream.h> +#include <iomanip.h> #include "linkchan.h" #include "bufferstore.h" +#include "bufferarray.h" linkChan::linkChan(ncp * _ncpController):channel(_ncpController) { + registerSer = 0x1234; + ncpConnect(); } void linkChan:: ncpDataCallback(bufferStore & a) { + int len = a.getLen(); if (verbose & LINKCHAN_DEBUG_LOG) { cout << "linkchan: << msg "; if (verbose & LINKCHAN_DEBUG_DUMP) cout << a << endl; else - cout << a.getLen() << endl; + cout << len << endl; } + if ((len > 7) && (a.getByte(0) == 1)) { + unsigned int ser = a.getWord(1); + int res = a.getWord(3); + // int dontknow = a.getWord(5); + const char *srvName = a.getString(7); + bufferArray newStack; + bufferStore se; + + if (verbose & LINKCHAN_DEBUG_LOG) + cout << "linkchan: received registerAck: ser=0x" << hex << setw(4) + << setfill(0) << ser << " res=" << res << " srvName=\"" + << srvName << "\"" << endl; + + while (!registerStack.empty()) { + se = registerStack.popBuffer(); + if (se.getWord(0) == ser) { + if (verbose & LINKCHAN_DEBUG_LOG) + cout << "linkchan: found ser=0x" << hex << setw(4) << + setfill(0) << se.getWord(0) << + " on stack -> callBack to waiting chan" << endl; + ncpDoRegisterAck((int)se.getWord(2)); + } else + newStack.pushBuffer(se); + } + registerStack = newStack; + return; + } + cerr << "linkchan: unknown message " << a.getByte(0) << endl; } -const char *linkChan:: +char *linkChan:: getNcpConnectName() { - return "LINK.*"; + return "LINK"; } void linkChan:: @@ -63,3 +96,25 @@ ncpConnectTerminate() cout << "linkchan: << ctrm" << endl; terminateWhenAsked(); } + +void linkChan:: +ncpConnectNak() +{ + ncpConnectTerminate(); +} + +void linkChan:: +Register(channel *ch) +{ + bufferStore a; + bufferStore stack; + + stack.addWord(registerSer); + stack.addWord(ch->getNcpChannel()); + registerStack.pushBuffer(stack); + a.addByte(0); + a.addWord(registerSer++); + a.addString(ch->getNcpConnectName()); + a.addByte(0); + ncpSend(a); +} diff --git a/ncpd/linkchan.h b/ncpd/linkchan.h index 2e2f7b9..4be75d0 100644 --- a/ncpd/linkchan.h +++ b/ncpd/linkchan.h @@ -26,6 +26,7 @@ #define _linkchan_h_ #include "channel.h" +#include "bufferarray.h" #define LINKCHAN_DEBUG_LOG 1 #define LINKCHAN_DEBUG_DUMP 2 @@ -35,9 +36,15 @@ class linkChan : public channel { linkChan(ncp *ncpController); void ncpDataCallback(bufferStore &a); - const char *getNcpConnectName(); + char *getNcpConnectName(); void ncpConnectAck(); void ncpConnectTerminate(); + void ncpConnectNak(); + void ncpRegisterAck() {} + void Register(channel *); + private: + int registerSer; + bufferArray registerStack; }; #endif diff --git a/ncpd/main.cc b/ncpd/main.cc index 101d7aa..3a0ddb6 100644 --- a/ncpd/main.cc +++ b/ncpd/main.cc @@ -52,7 +52,7 @@ checkForNewSocketConnection(ppsocket & skt, int &numScp, socketChan ** scp, ncp cout << "New socket connection from " << peer << endl; if ((numScp == 7) || (!a->gotLinkChannel())) { bufferStore a; - a.addStringT("No psion"); + a.addStringT("No Psion Connected\n"); next->sendBufferStore(a); next->closeSocket(); } else @@ -119,8 +119,16 @@ main(int argc, char **argv) pverbose |= PKT_DEBUG_LOG; if (!strcmp(argv[i], "pd")) pverbose |= PKT_DEBUG_DUMP; + if (!strcmp(argv[i], "ph")) + lverbose |= PKT_DEBUG_HANDSHAKE; if (!strcmp(argv[i], "m")) verbose = true; + if (!strcmp(argv[i], "all")) { + nverbose = NCP_DEBUG_LOG | NCP_DEBUG_DUMP; + lverbose = LNK_DEBUG_LOG | LNK_DEBUG_DUMP; + pverbose = PKT_DEBUG_LOG | PKT_DEBUG_DUMP; + verbose = true; + } } else if (!strcmp(argv[i], "-b") && i + 1 < argc) { baudRate = atoi(argv[++i]); } else if (!strcmp(argv[i], "-d")) { @@ -152,7 +160,7 @@ main(int argc, char **argv) } ncp *a = new ncp(serialDevice, baudRate, iow); int numScp = 0; - socketChan *scp[8]; + socketChan *scp[MAX_CHANNEL+1]; a->setVerbose(nverbose); a->setLinkVerbose(lverbose); diff --git a/ncpd/ncp.cc b/ncpd/ncp.cc index b13ba62..e1bf96a 100644 --- a/ncpd/ncp.cc +++ b/ncpd/ncp.cc @@ -41,9 +41,10 @@ ncp::ncp(const char *fname, int baud, IOWatch & iow) l = new link(fname, baud, iow); failed = false; verbose = 0; + protocolVersion = PV_SERIES_5; // until detected on receipt of INFO // init channels - for (int i = 0; i < 8; i++) + for (int i = 0; i < MAX_CHANNEL; i++) channelPtr[i] = NULL; } @@ -54,13 +55,13 @@ ncp::~ncp() void ncp:: reset() { - for (int i = 0; i < 8; i++) { + for (int i = 0; i < MAX_CHANNEL; i++) { if (channelPtr[i]) channelPtr[i]->terminateWhenAsked(); channelPtr[i] = NULL; } failed = false; - gotLinkChan = false; + lChan = NULL; l->reset(); } @@ -100,6 +101,12 @@ setPktVerbose(short int _verbose) l->setPktVerbose(_verbose); } +short int ncp:: +getProtocolVersion() +{ + return protocolVersion; +} + void ncp:: poll() { @@ -153,6 +160,7 @@ void ncp:: decodeControlMessage(bufferStore & buff) { int remoteChan = buff.getByte(0); + short int ver; interControllerMessageType imt = (interControllerMessageType) buff.getByte(1); buff.discardFirstBytes(2); if (verbose & NCP_DEBUG_LOG) @@ -162,7 +170,7 @@ decodeControlMessage(bufferStore & buff) { if (verbose & NCP_DEBUG_LOG) { if (verbose & NCP_DEBUG_DUMP) - cout << " " << buff; + cout << " [" << buff << "]"; cout << endl; } int localChan; @@ -174,15 +182,20 @@ decodeControlMessage(bufferStore & buff) b.addByte(0x0); controlChannel(localChan, NCON_MSG_CONNECT_RESPONSE, b); + // NOTE: we don't allow connections from the + // Psion to any local "processes" other than + // LINK.* - Matt might need to change this for + // his NCP<->TCP/IP bridge code... + if (!strcmp(buff.getString(0), "LINK.*")) { - if (gotLinkChan) + if (lChan) failed = true; if (verbose & NCP_DEBUG_LOG) cout << "ncp: Link UP" << endl; - channelPtr[localChan] = new linkChan(this); - channelPtr[localChan]->setNcpChannel(localChan); - channelPtr[localChan]->ncpConnectAck(); - gotLinkChan = true; + channelPtr[localChan] = lChan = new linkChan(this); + lChan->setNcpChannel(localChan); + lChan->ncpConnectAck(); + lChan->setVerbose(verbose); } else { if (verbose & NCP_DEBUG_LOG) cout << "ncp: Link DOWN" << endl; @@ -196,7 +209,7 @@ decodeControlMessage(bufferStore & buff) { int forChan = buff.getByte(0); if (verbose & NCP_DEBUG_LOG) - cout << "ch=" << forChan << " stat="; + cout << " ch=" << forChan << " stat="; if (buff.getByte(1) == 0) { if (verbose & NCP_DEBUG_LOG) cout << "OK" << endl; @@ -205,28 +218,43 @@ decodeControlMessage(bufferStore & buff) channelPtr[forChan]->ncpConnectAck(); } else { if (verbose & NCP_DEBUG_LOG) - cout << "ncp: message for unknown channel\n"; + cout << "ncp: message for unknown channel" << endl; } } else { if (verbose & NCP_DEBUG_LOG) cout << "Unknown " << (int) buff.getByte(1) << endl; - channelPtr[forChan]->ncpConnectTerminate(); + channelPtr[forChan]->ncpConnectNak(); } } break; case NCON_MSG_NCP_INFO: - if (buff.getByte(0) == 6) { + ver = buff.getByte(0); + // Series 3c returns '3', as does mclink. PsiWin 1.1 + // returns version 2. We return whatever version we're + // sent, which is rather crude, but works for Series 3 + // and probably 5. If Symbian have changed EPOC Connect + // for the Series 5mx/7, this may need to change. + // + if (ver == PV_SERIES_5 || ver == PV_SERIES_3) { bufferStore b; + protocolVersion = ver; if (verbose & NCP_DEBUG_LOG) { if (verbose & NCP_DEBUG_DUMP) - cout << " " << buff; + cout << " [" << buff << "]"; cout << endl; } - b.addByte(6); - b.addDWord(0); + // Fake NCP version 2 for a Series 3 (behave like PsiWin 1.1) + if (ver == PV_SERIES_3) + ver = 2; + b.addByte(ver); + // Do we send a time of 0 or a real time? + // The Psion uses this to determine whether to + // restart. (See protocol docs for details) + // b.addDWord(0); + b.addDWord(time(NULL)); controlChannel(0, NCON_MSG_NCP_INFO, b); } else - cout << "ALERT!!!! Protocol-Version is NOT 6!! (No Series 5?)!" << endl; + cout << "ALERT!!!! Unexpected Protocol Version!! (No Series 5/3?)!" << endl; break; case NCON_MSG_CHANNEL_DISCONNECT: if (verbose & NCP_DEBUG_LOG) @@ -240,7 +268,7 @@ decodeControlMessage(bufferStore & buff) default: if (verbose & NCP_DEBUG_LOG) { if (verbose & NCP_DEBUG_DUMP) - cout << " " << buff; + cout << " [" << buff << "]"; cout << endl; } } @@ -249,24 +277,53 @@ decodeControlMessage(bufferStore & buff) int ncp:: getFirstUnusedChan() { - for (int cNum = 1; cNum < 8; cNum++) { + for (int cNum = 1; cNum < MAX_CHANNEL; cNum++) { if (channelPtr[cNum] == NULL) { + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: getFirstUnusedChan=" << cNum << endl; return cNum; } } return 0; } +void ncp:: +RegisterAck(int chan) +{ + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: RegisterAck: chan=" << chan << endl; + for (int cNum = 1; cNum < MAX_CHANNEL; cNum++) { + channel *ch = channelPtr[cNum]; + if (ch->getNcpChannel() == chan) { + ch->ncpRegisterAck(); + return; + } + } + cerr << "ncp: RegisterAck: no channel to deliver" << endl; +} + +void ncp:: +Register(channel * ch) +{ + if (lChan) + lChan->Register(ch); + else + cerr << "ncp: Register without established lChan" << endl; +} + int ncp:: connect(channel * ch) { // look for first unused chan - int cNum = getFirstUnusedChan(); + int cNum = ch->getNcpChannel(); + if (cNum == 0) + cNum = getFirstUnusedChan(); if (cNum > 0) { channelPtr[cNum] = ch; ch->setNcpChannel(cNum); bufferStore b; b.addString(ch->getNcpConnectName()); + b.addString(".*"); b.addByte(0); controlChannel(cNum, NCON_MSG_CONNECT_TO_SERVER, b); return cNum; @@ -304,6 +361,8 @@ void ncp:: disconnect(int channel) { channelPtr[channel]->terminateWhenAsked(); + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: disconnect: channel=" << channel << endl; channelPtr[channel] = NULL; bufferStore b; b.addByte(remoteChanList[channel]); @@ -327,7 +386,7 @@ hasFailed() bool ncp:: gotLinkChannel() { - return gotLinkChan; + return (lChan != NULL); } char *ncp:: @@ -27,12 +27,14 @@ #include "bool.h" #include "bufferstore.h" +#include "linkchan.h" class link; class channel; class IOWatch; #define NCP_DEBUG_LOG 1 #define NCP_DEBUG_DUMP 2 +#define MAX_CHANNEL 8 class ncp { public: @@ -40,6 +42,8 @@ class ncp { ~ncp(); int connect(channel *c); // returns channel, or -1 if failure + void Register(channel *c); + void RegisterAck(int); void disconnect(int channel); void send(int channel, bufferStore &a); void poll(); @@ -53,6 +57,7 @@ class ncp { short int getLinkVerbose(); void setPktVerbose(short int); short int getPktVerbose(); + short int getProtocolVersion(); private: enum c { MAX_LEN = 200, LAST_MESS = 1, NOT_LAST_MESS = 2 }; @@ -67,6 +72,7 @@ class ncp { NCON_MSG_CHANNEL_DISCONNECT=7, NCON_MSG_NCP_END=8 }; + enum protocolVersionType { PV_SERIES_5 = 6, PV_SERIES_3 = 3 }; int getFirstUnusedChan(); void decodeControlMessage(bufferStore &buff); void controlChannel(int chan, enum interControllerMessageType t, bufferStore &command); @@ -74,11 +80,12 @@ class ncp { link *l; unsigned short verbose; - channel *channelPtr[8]; - bufferStore messageList[8]; - int remoteChanList[8]; - bool gotLinkChan; + channel *channelPtr[MAX_CHANNEL+1]; + bufferStore messageList[MAX_CHANNEL+1]; + int remoteChanList[MAX_CHANNEL+1]; bool failed; + short int protocolVersion; + linkChan *lChan; }; #endif diff --git a/ncpd/packet.cc b/ncpd/packet.cc index 8099bb9..26823c8 100644 --- a/ncpd/packet.cc +++ b/ncpd/packet.cc @@ -33,6 +33,7 @@ #include <iomanip.h> #include <errno.h> #include <sys/ioctl.h> +#include <termios.h> extern "C" { #include "mp_serial.h" @@ -170,6 +171,10 @@ get(unsigned char &type, bufferStore & ret) } if (res < 0) return false; + // XXX Solaris returns 0 on non blocking TTY lines + // even when VMIN > 0 + if( res == 0 && inLen == 0 ) + return false; if (inLen >= BUFFERLEN) { cerr << "packet: input buffer overflow!!!!" << endl; inLen = 0; @@ -256,13 +261,17 @@ linkFailed() int res = ioctl(fd, TIOCMGET, &arg); if (res < 0) failed = true; - if (verbose & PKT_DEBUG_DUMP) + if (verbose & PKT_DEBUG_HANDSHAKE) cout << "packet: DTR:" << ((arg & TIOCM_DTR)?1:0) << " RTS:" << ((arg & TIOCM_RTS)?1:0) << " DCD:" << ((arg & TIOCM_CAR)?1:0) << " DSR:" << ((arg & TIOCM_DSR)?1:0) << " CTS:" << ((arg & TIOCM_CTS)?1:0) << endl; +#ifdef sun + if ((arg & TIOCM_CTS) == 0) +#else if (((arg & TIOCM_DSR) == 0) || ((arg & TIOCM_CTS) == 0)) +#endif failed = true; if ((verbose & PKT_DEBUG_LOG) && failed) cout << "packet: linkFAILED\n"; diff --git a/ncpd/packet.h b/ncpd/packet.h index 77ca4e9..26d4282 100644 --- a/ncpd/packet.h +++ b/ncpd/packet.h @@ -34,6 +34,7 @@ class IOWatch; #define PKT_DEBUG_LOG 1 #define PKT_DEBUG_DUMP 2 +#define PKT_DEBUG_HANDSHAKE 4 class packet { public: @@ -63,7 +64,7 @@ class packet { int outLen; int termLen; int fd; - bool verbose; + short int verbose; bool esc; char *devname; int baud; diff --git a/ncpd/socketchan.cc b/ncpd/socketchan.cc index d78d3b6..a7d612e 100644 --- a/ncpd/socketchan.cc +++ b/ncpd/socketchan.cc @@ -39,6 +39,7 @@ iow(_iow) { skt = _skt; connectName = 0; + connectTry = 0; iow.addIO(skt->socket()); connected = false; } @@ -61,12 +62,63 @@ ncpDataCallback(bufferStore & a) cerr << "socketchan: Connect without name!!!\n"; } -const char *socketChan:: +char *socketChan:: getNcpConnectName() { return connectName; } +// NCP Command processing +bool socketChan:: +ncpCommand(bufferStore & a) +{ +cerr << "socketChan:: received NCP command (" << a << ")" << endl; + // str is guaranteed to begin with NCP$, and all NCP commands are + // greater than or equal to 8 characters in length. + const char *str = a.getString(); + // unsigned long len = a.getLen(); + bool ok = false; + + if (!strncmp(str+4, "INFO", 4)) { + // Send information discovered during the receipt of the + // NCON_MSG_NCP_INFO message. + a.init(); + switch (ncpProtocolVersion()) { + case PV_SERIES_3: + a.addStringT("Series 3"); + break; + case PV_SERIES_5: + a.addStringT("Series 5"); + break; + default: + cerr << "ncpd: protocol version not known" << endl; + a.addStringT("Unknown!"); + break; + } + skt->sendBufferStore(a); + ok = true; + } else if (!strncmp(str+4, "CONN", 4)) { + // Connect to a channel that was placed in 'pending' mode, by + // checking the channel table against the ID... + // DO ME LATER + ok = true; + } else if (!strncmp(str+4, "CHAL", 4)) { + // Challenge + // The idea is that the channel stays in 'secure' mode until a + // valid RESP is received + // DO ME LATER + ok = true; + } else if (!strncmp(str+4, "RESP", 4)) { + // Reponse - here is the plaintext as sent in the CHAL - the + // channel will only open up if this matches what ncpd has for + // the encrypted plaintext. + // DO ME LATER + ok = true; + } + return ok; +} + + void socketChan:: ncpConnectAck() { @@ -74,24 +126,77 @@ ncpConnectAck() a.addStringT("Ok"); skt->sendBufferStore(a); connected = true; + connectTry = 3; } void socketChan:: ncpConnectTerminate() { bufferStore a; + connectTry = 0; a.addStringT("Close"); skt->sendBufferStore(a); terminateWhenAsked(); } void socketChan:: +ncpRegisterAck() +{ + connectTry++; + ncpConnect(); +} + +void socketChan:: +ncpConnectNak() +{ + if (!connectName || (connectTry > 1)) + ncpConnectTerminate(); + else { + connectTry++; + ncpRegister(); + } +} + +void socketChan:: socketPoll() { if (connectName == 0) { bufferStore a; if (skt->getBufferStore(a, false) == 1) { + // A client has connected, and is announcing who it + // is... e.g. "SYS$RFSV.*" + // + // An NCP Channel can be in 'Control' or 'Data' mode. + // Initially, it is in 'Control' mode, and can accept + // certain commands. + // + // When a command is received that ncpd does not + // understand, this is assumed to be a request to + // connect to the remote service of that name, and enter + // 'data' mode. + // + // Later, there might be an explicit command to enter + // 'data' mode, and also a challenge-response protocol + // before any connection can be made. + // + // All commands begin with "NCP$". + + // There is a magic process name called "NCP$INFO.*" + // which is announced by the rfsvfactory. This causes a + // response to be issued containing the NCP version + // number. The rfsvfactory will create the correct type + // of RFSV protocol handler, which will then announce + // itself. So, first time in here, we might get the + // NCP$INFO.* + if (a.getLen() > 8 && !strncmp(a.getString(), "NCP$", 4)) { + if (!ncpCommand(a)) + cerr << "ncpd: command " << a << " unrecognised." << endl; + return; + } + + // This isn't a command, it's a remote process. Connect. connectName = strdup(a.getString()); + connectTry++; ncpConnect(); } } else if (connected) { diff --git a/ncpd/socketchan.h b/ncpd/socketchan.h index e352b36..5fe7a13 100644 --- a/ncpd/socketchan.h +++ b/ncpd/socketchan.h @@ -36,17 +36,23 @@ public: virtual ~socketChan(); void ncpDataCallback(bufferStore& a); - const char* getNcpConnectName(); + char* getNcpConnectName(); void ncpConnectAck(); + void ncpRegisterAck(); + void ncpDoRegisterAck(int) {} void ncpConnectTerminate(); + void ncpConnectNak(); bool isConnected() const; void socketPoll(); private: + enum protocolVersionType { PV_SERIES_5 = 6, PV_SERIES_3 = 3 }; + bool ncpCommand(bufferStore &a); ppsocket* skt; IOWatch &iow; char* connectName; bool connected; + int connectTry; }; #endif diff --git a/plpftp/ftp.cc b/plpftp/ftp.cc index 2341ce5..45ec2eb 100644 --- a/plpftp/ftp.cc +++ b/plpftp/ftp.cc @@ -32,10 +32,12 @@ #include <unistd.h> #include <sys/time.h> #include <sys/stat.h> +#include <signal.h> #include "defs.h" #include "ftp.h" -#include "rfsv32.h" +#include "rfsv.h" +#include "rpcs.h" #include "bufferarray.h" #include "bufferstore.h" @@ -49,6 +51,12 @@ extern "C" { } #endif +static char psionDir[1024]; +static rfsv *comp_a; +static rpcs *comp_r; +static int continueRunning; + + void ftp:: resetUnixPwd() { @@ -59,8 +67,6 @@ resetUnixPwd() ftp::ftp() { resetUnixPwd(); - strcpy(psionDir, DEFAULT_DRIVE); - strcat(psionDir, DEFAULT_BASE_DIRECTORY); } ftp::~ftp() @@ -68,29 +74,33 @@ ftp::~ftp() } void ftp::usage() { - cerr << "Unknown command" << endl; - cerr << " pwd" << endl; - cerr << " ren <oldname> <newname>" << endl; - cerr << " touch <psionfile>" << endl; - cerr << " gtime <psionfile>" << endl; - cerr << " test <psionfile>" << endl; - cerr << " gattr <psionfile>" << endl; - cerr << " sattr [[-|+]rhsa] <psionfile>" << endl; - cerr << " devs" << endl; - cerr << " dir|ls" << endl; - cerr << " dircnt" << endl; - cerr << " cd <dir>" << endl; - cerr << " lcd <dir>" << endl; - cerr << " !<system command>" << endl; - cerr << " get <psionfile>" << endl; - cerr << " put <unixfile>" << endl; - cerr << " mget <shellpattern>" << endl; - cerr << " mput <shellpattern>" << endl; - cerr << " del|rm <psionfile>" << endl; - cerr << " mkdir <psiondir>" << endl; - cerr << " rmdir <psiondir>" << endl; - cerr << " prompt" << endl; - cerr << " bye" << endl; + cout << "Known FTP commands:" << endl << endl; + cout << " pwd" << endl; + cout << " ren <oldname> <newname>" << endl; + cout << " touch <psionfile>" << endl; + cout << " gtime <psionfile>" << endl; + cout << " test <psionfile>" << endl; + cout << " gattr <psionfile>" << endl; + cout << " sattr [[-|+]rhsa] <psionfile>" << endl; + cout << " devs" << endl; + cout << " dir|ls" << endl; + cout << " dircnt" << endl; + cout << " cd <dir>" << endl; + cout << " lcd <dir>" << endl; + cout << " !<system command>" << endl; + cout << " get <psionfile>" << endl; + cout << " put <unixfile>" << endl; + cout << " mget <shellpattern>" << endl; + cout << " mput <shellpattern>" << endl; + cout << " del|rm <psionfile>" << endl; + cout << " mkdir <psiondir>" << endl; + cout << " rmdir <psiondir>" << endl; + cout << " prompt" << endl; + cout << " hash" << endl; + cout << " bye" << endl; + cout << endl << "Known RPC commands:" << endl << endl; + cout << " ps" << endl; + cout << " kill <pid|'all'>" << endl; } static int Wildmat(const char *s, char *p); @@ -146,8 +156,36 @@ Wildmat(const char *s, char *p) return (*s == '\0'); } +static int +checkAbortNoHash(long) +{ + return continueRunning; +} + +static int +checkAbortHash(long) +{ + if (continueRunning) { + printf("#"); fflush(stdout); + } + return continueRunning; +} + +static void +sigint_handler(int i) { + continueRunning = 0; + signal(SIGINT, sigint_handler); +} + +static void +sigint_handler2(int i) { + continueRunning = 0; + fclose(stdin); + signal(SIGINT, sigint_handler2); +} + int ftp:: -session(rfsv32 & a, int xargc, char **xargv) +session(rfsv & a, rpcs & r, int xargc, char **xargv) { int argc; char *argv[10]; @@ -155,6 +193,8 @@ session(rfsv32 & a, int xargc, char **xargv) char f2[256]; long res; bool prompt = true; + bool hash = false; + cpCallback_t cab = checkAbortNoHash; bool once = false; if (xargc > 1) { @@ -163,15 +203,107 @@ session(rfsv32 & a, int xargc, char **xargv) for (int i = 0; i < argc; i++) argv[i] = xargv[i+1]; } + if (!once) { + bufferArray b; + if (!r.getOwnerInfo(b)) { + int machType; + r.getMachineType(machType); + cout << "Connected to "; + switch (machType) { + case rpcs::PSI_MACH_UNKNOWN: + cout << "an unknown Device"; + break; + case rpcs::PSI_MACH_PC: + cout << "a PC"; + break; + case rpcs::PSI_MACH_MC: + cout << "a MC"; + break; + case rpcs::PSI_MACH_HC: + cout << "a HC"; + break; + case rpcs::PSI_MACH_S3: + cout << "a Serie 3"; + break; + case rpcs::PSI_MACH_S3A: + cout << "a Series 3a, 3c or 3mx"; + break; + case rpcs::PSI_MACH_WORKABOUT: + cout << "a Workabout"; + break; + case rpcs::PSI_MACH_SIENNA: + cout << "a Sienna"; + break; + case rpcs::PSI_MACH_S3C: + cout << "a Series 3c"; + break; + case rpcs::PSI_MACH_S5: + cout << "a Series 5"; + break; + case rpcs::PSI_MACH_WINC: + cout << "a WinC"; + break; + default: + cout << "an undefined Device"; + break; + } + cout << ", OwnerInfo:" << endl; + while (!b.empty()) + cout << " " << b.pop().getString() << endl; + cout << endl; + } + } + + if (!strcmp(DDRIVE, "AUTO")) { + long devbits; + long vtotal, vfree, vattr, vuniqueid; + int i; + + strcpy(defDrive, "::"); + if (a.devlist(&devbits) == 0) { + + for (i = 0; i < 26; i++) { + if ((devbits & 1) && a.devinfo(i, &vfree, &vtotal, &vattr, &vuniqueid)) { + defDrive[0] = 'A' + i; + break; + } + devbits >>= 1; + } + } + if (!strcmp(defDrive, "::")) { + cerr << "FATAL: Couln't find default Drive" << endl; + return -1; + } + } else + strcpy(defDrive, DDRIVE); + strcpy(psionDir, defDrive); + strcat(psionDir, DBASEDIR); + comp_a = &a; + if (!once) { + cout << "Psion dir is: \"" << psionDir << "\"" << endl; + initReadline(); + } + continueRunning = 1; + signal(SIGINT, sigint_handler); do { if (!once) getCommand(argc, argv); + if (!strcmp(argv[0], "help")) { + usage(); + continue; + } if (!strcmp(argv[0], "prompt")) { prompt = !prompt; cout << "Prompting now " << (prompt?"on":"off") << endl; continue; } + if (!strcmp(argv[0], "hash")) { + hash = !hash; + cout << "Hash printing now " << (hash?"on":"off") << endl; + cab = (hash) ? checkAbortHash : checkAbortNoHash; + continue; + } if (!strcmp(argv[0], "pwd")) { cout << "Local dir: \"" << localDir << "\"" << endl; cout << "Psion dir: \"" << psionDir << "\"" << endl; @@ -199,6 +331,17 @@ session(rfsv32 & a, int xargc, char **xargv) strcat(f1, argv[1]); if ((res = a.fgeteattr(f1, &attr, &size, &time)) != 0) errprint(res, a); + else { + // never used to do this + char dateBuff[100]; + struct tm *t; + t = localtime(&time); + strftime(dateBuff, 100, "%c", t); + cout << a.opAttr(attr); + cout << " " << dec << setw(10) << setfill(' ') << size; + cout << " " << dateBuff; + cout << " " << argv[1] << endl; + } continue; } if (!strcmp(argv[0], "gattr") && (argc == 2)) { @@ -207,11 +350,13 @@ session(rfsv32 & a, int xargc, char **xargv) strcat(f1, argv[1]); if ((res = a.fgetattr(f1, &attr)) != 0) errprint(res, a); - else - cout << hex << setw(4) << setfill('0') << attr << endl; + else { + cout << hex << setw(4) << setfill('0') << attr; + cout << " (" << a.opAttr(attr) << ")" << endl; + } continue; } - if (!strcmp(argv[0], "gtime")) { + if (!strcmp(argv[0], "gtime") && (argc == 2)) { long mtime; strcpy(f1, psionDir); strcat(f1, argv[1]); @@ -226,7 +371,7 @@ session(rfsv32 & a, int xargc, char **xargv) } continue; } - if (!strcmp(argv[0], "sattr")) { + if (!strcmp(argv[0], "sattr") && (argc == 2)) { long attr[2]; int aidx = 0; char *p = argv[1]; @@ -287,7 +432,8 @@ session(rfsv32 & a, int xargc, char **xargv) if (vname != NULL) { cout << (char) ('A' + i) << " " << hex << setw(4) << setfill('0') << vattr << " " << - setw(12) << setfill(' ') << setiosflags(ios::left) << vname << resetiosflags(ios::left) << dec << setw(9) << + setw(12) << setfill(' ') << setiosflags(ios::left) << + vname << resetiosflags(ios::left) << dec << setw(9) << vtotal << setw(9) << vfree << setw(10) << vuniqueid << endl; free(vname); } @@ -298,14 +444,14 @@ session(rfsv32 & a, int xargc, char **xargv) errprint(res, a); continue; } - if ((!strcmp(argv[0], "ls")) || (!strcmp(argv[0], "dir"))) { + if (!strcmp(argv[0], "ls") || !strcmp(argv[0], "dir")) { bufferArray files; if ((res = a.dir(psionDir, &files)) != 0) errprint(res, a); else while (!files.empty()) { bufferStore s; - s = files.popBuffer(); + s = files.pop(); long date = s.getDWord(0); long size = s.getDWord(4); long attr = s.getDWord(8); @@ -313,15 +459,7 @@ session(rfsv32 & a, int xargc, char **xargv) struct tm *t; t = localtime(&date); strftime(dateBuff, 100, "%c", t); - cout << ((attr & rfsv32::PSI_ATTR_DIRECTORY) ? "d" : "-"); - cout << ((attr & rfsv32::PSI_ATTR_RONLY) ? "-" : "w"); - cout << ((attr & rfsv32::PSI_ATTR_HIDDEN) ? "h" : "-"); - cout << ((attr & rfsv32::PSI_ATTR_SYSTEM) ? "s" : "-"); - cout << ((attr & rfsv32::PSI_ATTR_ARCHIVE) ? "a" : "-"); - cout << ((attr & rfsv32::PSI_ATTR_VOLUME) ? "v" : "-"); - cout << ((attr & rfsv32::PSI_ATTR_NORMAL) ? "n" : "-"); - cout << ((attr & rfsv32::PSI_ATTR_TEMPORARY) ? "t" : "-"); - cout << ((attr & rfsv32::PSI_ATTR_COMPRESSED) ? "c" : "-"); + cout << a.opAttr(attr); cout << " " << dec << setw(10) << setfill(' ') << size; cout << " " << dateBuff; cout << " " << s.getString(12) << endl; @@ -332,9 +470,10 @@ session(rfsv32 & a, int xargc, char **xargv) if (argc == 1) resetUnixPwd(); else { - if (chdir(argv[1]) == 0) - strcpy(localDir, argv[1]); - else + if (chdir(argv[1]) == 0) { + getcwd(localDir, sizeof(localDir)); + strcat(localDir, "/"); + } else cerr << "No such directory" << endl << "Keeping original directory \"" << localDir << "\"" << endl; } @@ -342,8 +481,8 @@ session(rfsv32 & a, int xargc, char **xargv) } if (!strcmp(argv[0], "cd")) { if (argc == 1) { - strcpy(psionDir, DEFAULT_DRIVE); - strcat(psionDir, DEFAULT_BASE_DIRECTORY); + strcpy(psionDir, defDrive); + strcat(psionDir, DBASEDIR); } else { long tmp; if (!strcmp(argv[1], "..")) { @@ -369,10 +508,16 @@ session(rfsv32 & a, int xargc, char **xargv) } if ((f1[strlen(f1) -1] != '/') && (f1[strlen(f1) -1] != '\\')) strcat(f1,"\\"); - if ((res = a.dircount(f1, &tmp)) == 0) + if ((res = a.dircount(f1, &tmp)) == 0) { + for (char *p = f1; *p; p++) + if (*p == '/') + *p = '\\'; strcpy(psionDir, f1); - else + } + else { + errprint(res, a); cerr << "Keeping original directory \"" << psionDir << "\"" << endl; + } } continue; } @@ -389,9 +534,14 @@ session(rfsv32 & a, int xargc, char **xargv) else strcat(f2, argv[2]); gettimeofday(&stime, 0L); - if ((res = a.copyFromPsion(f1, f2)) != 0) + if ((res = a.copyFromPsion(f1, f2, cab)) != 0) { + if (hash) + cout << endl; + continueRunning = 1; errprint(res, a); - else { + } else { + if (hash) + cout << endl; gettimeofday(&etime, 0L); long dsec = etime.tv_sec - stime.tv_sec; long dhse = (etime.tv_usec / 10000) - @@ -419,7 +569,7 @@ session(rfsv32 & a, int xargc, char **xargv) } while (!files.empty()) { bufferStore s; - s = files.popBuffer(); + s = files.pop(); char temp[100]; long attr = s.getDWord(8); @@ -441,23 +591,29 @@ session(rfsv32 & a, int xargc, char **xargv) } while (temp[1] != 0 || (temp[0] != 'y' && temp[0] != 'n')); if (temp[0] != 'n') { strcpy(f1, psionDir); - strcat(f1, s.getString()); + strcat(f1, s.getString(12)); strcpy(f2, localDir); - strcat(f2, s.getString()); + strcat(f2, s.getString(12)); if (temp[0] == 'l') { for (char *p = f2; *p; p++) *p = tolower(*p); } - if ((res = a.copyFromPsion(f1, f2)) != 0) { + if ((res = a.copyFromPsion(f1, f2, cab)) != 0) { + if (hash) + cout << endl; + continueRunning = 1; errprint(res, a); break; - } else + } else { + if (hash) + cout << endl; cout << "Transfer complete\n"; + } } } continue; } - if (!strcmp(argv[0], "put")) { + if (!strcmp(argv[0], "put") && (argc >= 2)) { struct timeval stime; struct timeval etime; struct stat stbuf; @@ -470,9 +626,14 @@ session(rfsv32 & a, int xargc, char **xargv) else strcat(f2, argv[2]); gettimeofday(&stime, 0L); - if ((res = a.copyToPsion(f1, f2)) != 0) + if ((res = a.copyToPsion(f1, f2, cab)) != 0) { + if (hash) + cout << endl; + continueRunning = 1; errprint(res, a); - else { + } else { + if (hash) + cout << endl; gettimeofday(&etime, 0L); long dsec = etime.tv_sec - stime.tv_sec; long dhse = (etime.tv_usec / 10000) - @@ -526,11 +687,17 @@ session(rfsv32 & a, int xargc, char **xargv) if (temp[0] == 'y') { strcpy(f2, psionDir); strcat(f2, de->d_name); - if ((res = a.copyToPsion(f1, f2)) != 0) { + if ((res = a.copyToPsion(f1, f2, cab)) != 0) { + if (hash) + cout << endl; + continueRunning = 1; errprint(res, a); break; - } else + } else { + if (hash) + cout << endl; cout << "Transfer complete\n"; + } } } } while (de); @@ -539,22 +706,22 @@ session(rfsv32 & a, int xargc, char **xargv) cerr << "Error in directory name \"" << localDir << "\"\n"; continue; } - if (!strcmp(argv[0], "del") || - !strcmp(argv[0], "rm")) { + if ((!strcmp(argv[0], "del") || + !strcmp(argv[0], "rm")) && (argc == 2)) { strcpy(f1, psionDir); strcat(f1, argv[1]); if ((res = a.remove(f1)) != 0) errprint(res, a); continue; } - if (!strcmp(argv[0], "mkdir")) { + if (!strcmp(argv[0], "mkdir") && (argc == 2)) { strcpy(f1, psionDir); strcat(f1, argv[1]); if ((res = a.mkdir(f1)) != 0) errprint(res, a); continue; } - if (!strcmp(argv[0], "rmdir")) { + if (!strcmp(argv[0], "rmdir") && (argc == 2)) { strcpy(f1, psionDir); strcat(f1, argv[1]); if ((res = a.rmdir(f1)) != 0) @@ -568,79 +735,274 @@ session(rfsv32 & a, int xargc, char **xargv) strcat(cmd, " "); strcat(cmd, argv[i]); } - system(cmd); + if (strlen(cmd)) + system(cmd); + else { + char *sh; + cout << "Starting subshell ...\n"; + sh = getenv("SHELL"); + if (!sh) + sh = "/bin/sh"; + system(sh); + } + continue; + } + // RPCS commands + // if (!strcmp(argv[0], "xxx")) { + // r.configOpen(); + // continue; + // } + if (!strcmp(argv[0], "run") && (argc >= 2)) { + char argbuf[1024]; + char cmdbuf[1024]; + + argbuf[0] = 0; + for (int i = 2; i < argc; i++) { + if (i > 2) { + strcat(argbuf, " "); + strcat(argbuf, argv[i]); + } else + strcpy(argbuf, argv[i]); + } + if (argv[1][1] != ':') { + strcpy(cmdbuf, psionDir); + strcat(cmdbuf, argv[1]); + } else + strcpy(cmdbuf, argv[1]); + r.execProgram(cmdbuf, argbuf); + continue; + } + if (!strcmp(argv[0], "kill") && (argc >= 2)) { + bufferArray tmp, tmp2; + bool anykilled = false; + r.queryDrive('C', tmp); + tmp2 = tmp; + for (int i = 1; i < argc; i++) { + int kpid; + tmp = tmp2; + if (!strcmp(argv[i], "all")) + kpid = -1; + else + sscanf(argv[i], "%d", &kpid); + while (!tmp.empty()) { + bufferStore bs = tmp.pop(); + tmp.pop(); + int pid = bs.getWord(0); + const char *proc = bs.getString(2); + if (kpid == -1 || kpid == pid) { + char pbuf[128]; + sprintf(pbuf, "%s.$%d", proc, pid); + r.stopProgram(pbuf); + anykilled = true; + } + } + if (kpid == -1) + break; + } + if (!anykilled) + cerr << "no such process" << endl; + continue; + } + if (!strcmp(argv[0], "ps")) { + bufferArray tmp; + r.queryDrive('C', tmp); + cout << "PID CMD ARGS" << endl; + while (!tmp.empty()) { + bufferStore bs = tmp.pop(); + bufferStore bs2 = tmp.pop(); + int pid = bs.getWord(0); + const char *proc = bs.getString(2); + const char *arg = bs2.getString(); + + printf("%5d %-12s %s\n", pid, proc, arg); + } continue; } if (strcmp(argv[0], "bye") && strcmp(argv[0], "quit")) - usage(); - } while (strcmp(argv[0], "bye") && strcmp(argv[0], "quit") && !once); + cerr << "syntax error. Try \"help\"" << endl; + } while (strcmp(argv[0], "bye") && strcmp(argv[0], "quit") && !once && + continueRunning); return a.getStatus(); } void ftp:: -errprint(long errcode, rfsv32 & a) { +errprint(long errcode, rfsv & a) { cerr << "Error: " << a.opErr(errcode) << endl; } -int ftp:: -convertName(const char *orig, char *retVal) +#if HAVE_LIBREADLINE +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 +}; + +static char *localfile_commands[] = { + "lcd ", "put ", "mput ", NULL +}; + +static char *remote_dir_commands[] = { + "cd ", "rmdir ", NULL +}; + +static bufferArray *comp_files = NULL; +static long maskAttr; + +static char* +filename_generator(char *text, int state) { - int len = strlen(orig); - char *temp = new char[len + 1]; - - for (int i = 0; i <= len; i++) { - if (orig[i] == '/') - temp[i] = '\\'; - else - temp[i] = orig[i]; + static int len; + + + if (!state) { + long res; + len = strlen(text); + if (comp_files) + delete comp_files; + comp_files = new bufferArray(); + if ((res = comp_a->dir(psionDir, comp_files)) != 0) { + cerr << "Error: " << comp_a->opErr(res) << endl; + return NULL; + } } - if (len == 0 || temp[1] != ':') { - // We can automatically supply a drive letter - strcpy(retVal, DEFAULT_DRIVE); + while (!comp_files->empty()) { + bufferStore s; + s = comp_files->pop(); + long attr = s.getDWord(8); - if (len == 0 || temp[0] != '\\') { - strcat(retVal, DEFAULT_BASE_DIRECTORY); - } else { - retVal[strlen(retVal) - 1] = 0; + if ((attr & maskAttr) == 0) + continue; + if (!(strncmp(s.getString(12), text, len))) { + char fnbuf[512]; + strcpy(fnbuf, s.getString(12)); + if (attr & 0x10) + strcat(fnbuf, "/"); + return (strdup(fnbuf)); } + } + return NULL; +} - strcat(retVal, temp); - } else { - strcpy(retVal, temp); +static char * +command_generator(char *text, int state) +{ + static int idx, len; + char *name; + + if (!state) { + idx = 0; + len = strlen(text); } - delete[]temp; + while ((name = all_commands[idx])) { + idx++; + if (!strncmp(name, text, len)) + return (strdup(name)); + } + return NULL; +} + +static int +null_completion() { return 0; } +static char ** +do_completion(char *text, int start, int end) +{ + char **matches = NULL; + + rl_completion_entry_function = (Function *)null_completion; + if (start == 0) + matches = completion_matches(text, command_generator); + else { + int idx = 0; + char *name; + + rl_filename_quoting_desired = 1; + while ((name = localfile_commands[idx])) { + idx++; + if (!strncmp(name, rl_line_buffer, strlen(name))) { + rl_completion_entry_function = NULL; + return NULL; + } + } + maskAttr = 0xffff; + idx = 0; + while ((name = remote_dir_commands[idx])) { + idx++; + if (!strncmp(name, rl_line_buffer, strlen(name))) + maskAttr = 0x0010; + } + + matches = completion_matches(text, filename_generator); + } + return matches; +} +#endif + +void ftp:: +initReadline(void) +{ +#if HAVE_LIBREADLINE + rl_readline_name = "plpftp"; + rl_completion_entry_function = (Function *)null_completion; + rl_attempted_completion_function = (CPPFunction *)do_completion; +#endif +} + void ftp:: getCommand(int &argc, char **argv) { - int ws; - char *bp; + int ws, quote; static char buf[1024]; buf[0] = 0; argc = 0; - while (!strlen(buf)) { - bp = readline("> "); + while (!strlen(buf) && continueRunning) { + signal(SIGINT, sigint_handler2); +#if HAVE_LIBREADLINE + char *bp = readline("> "); if (!bp) { strcpy(buf, "bye"); cout << buf << endl; } else { strcpy(buf, bp); +#if HAVE_LIBHISTORY add_history(buf); +#endif free(bp); } +#else + cout << "> "; + cout.flush(); + cin.getline(buf, 1023); + if (cin.eof()) { + strcpy(buf, "bye"); + cout << buf << endl; + } +#endif + signal(SIGINT, sigint_handler); } - ws = 1; + ws = 1; quote = 0; for (char *p = buf; *p; p++) - if ((*p == ' ') || (*p == '\t')) { - ws = 1; - *p = 0; - } else { - if (ws) - argv[argc++] = p; - ws = 0; + switch (*p) { + case ' ': + case '\t': + if (!quote) { + ws = 1; + *p = 0; + } + break; + case '"': + quote = 1 - quote; + if (!quote) + *p = 0; + break; + default: + if (ws) { + argv[argc++] = p; + } + ws = 0; } } diff --git a/plpftp/ftp.h b/plpftp/ftp.h index 38edf40..a89fd62 100644 --- a/plpftp/ftp.h +++ b/plpftp/ftp.h @@ -27,33 +27,39 @@ #include "bool.h" -class rfsv32; +class rfsv; +class rpcs; class bufferStore; class bufferArray; -#define DEFAULT_DRIVE "C:" -#define DEFAULT_BASE_DIRECTORY "\\" - class ftp { public: ftp(); ~ftp(); - int session(rfsv32 & a, int xargc, char **xargv); + int session(rfsv & a, rpcs & r, int xargc, char **xargv); private: void getCommand(int &argc, char **argv); + void initReadline(void); // utilities bool unixDirExists(const char *dir); void getUnixDir(bufferArray & files); void resetUnixPwd(); void usage(); - void errprint(long errcode, rfsv32 & a); + void errprint(long errcode, rfsv & a); void cd(const char *source, const char *cdto, char *dest); - int convertName(const char *orig, char *retVal); + // MJG: note, this isn't actually used anywhere + int convertName(const char *orig, char *retVal); +#ifdef HAVE_READLINE + char *filename_generator(char *, int); + char *command_generator(char *, int); + char **do_completion(char *, int, int); +#endif + char defDrive[9]; char localDir[1024]; - char psionDir[1024]; + // char psionDir[1024]; }; #endif diff --git a/plpftp/main.cc b/plpftp/main.cc index 816c58a..8d00574 100644 --- a/plpftp/main.cc +++ b/plpftp/main.cc @@ -31,7 +31,10 @@ #include "defs.h" #include "bool.h" #include "ppsocket.h" -#include "rfsv32.h" +#include "rfsv.h" +#include "rfsvfactory.h" +#include "rpcs.h" +#include "rpcsfactory.h" #include "ftp.h" #include "bufferstore.h" @@ -48,6 +51,7 @@ ftpHeader() cout << "PLPFTP Version " << VERSION; cout << " Copyright (C) 1999 Philip Proudman" << endl; cout << " Additions Copyright (C) 1999 Fritz Elfert <felfert@to.com>" << endl; + cout << " & (C) 1999 Matt Gumbley <matt@gumbley.demon.co.uk>" << endl; cout << "PLP comes with ABSOLUTELY NO WARRANTY;" << endl; cout << "This is free software, and you are welcome to redistribute it" << endl; cout << "under GPL conditions; see the COPYING file in the distribution." << endl; @@ -59,7 +63,9 @@ int main(int argc, char **argv) { ppsocket *skt; - rfsv32 *a; + ppsocket *skt2; + rfsv *a; + rpcs *r; ftp f; int status = 0; sigset_t sigset; @@ -80,10 +86,26 @@ main(int argc, char **argv) if (argc < 2) ftpHeader(); skt = new ppsocket(); - skt->connect(NULL, sockNum); - a = new rfsv32(skt); - status = f.session(*a, argc, argv); - - delete a; + if (!skt->connect(NULL, sockNum)) { + cout << "plpftp: could not connect to ncpd" << endl; + return 1; + } + skt2 = new ppsocket(); + if (!skt2->connect(NULL, sockNum)) { + cout << "plpftp: could not connect to ncpd" << endl; + return 1; + } + rfsvfactory *rf = new rfsvfactory(skt); + rpcsfactory *rp = new rpcsfactory(skt2); + a = rf->create(false); + r = rp->create(false); + if ((a != NULL) && (r != NULL)) { + status = f.session(*a, *r, argc, argv); + delete r; + delete a; + } else { + cout << "plpftp: could not create rfsv object" << endl; + status = 1; + } return status; } diff --git a/plpnfsd/main.cc b/plpnfsd/main.cc index 77f178a..206d902 100644 --- a/plpnfsd/main.cc +++ b/plpnfsd/main.cc @@ -8,10 +8,12 @@ #include <stdlib.h> #include <stdio.h> #include <signal.h> +#include <syslog.h> #include "defs.h" #include "bool.h" -#include "rfsv32.h" +#include "rfsv.h" +#include "rfsvfactory.h" #include "bufferstore.h" #include "bufferarray.h" #include "ppsocket.h" @@ -19,16 +21,30 @@ extern "C" { #include "rfsv_api.h" } -static rfsv32 *a; +static rfsv *a; +static rfsvfactory *rf; +static char *a_filename; +static long a_handle; +static long a_offset; +static long a_openmode; long rfsv_isalive() { - return (a->getStatus() == 0); + if (!a) { + a = rf->create(true); + if (a != NULL) + return (a->getStatus() == 0); + } + return 0; } long rfsv_dir(const char *file, dentry **e) { bufferArray entries; dentry *tmp; - long ret = a->dir(&(*file), &entries); + long ret; + + if (!a) + return -1; + ret = a->dir(&(*file), &entries); while (!entries.empty()) { bufferStore s; s = entries.popBuffer(); @@ -46,10 +62,14 @@ long rfsv_dir(const char *file, dentry **e) { } long rfsv_dircount(const char *file, long *count) { + if (!a) + return -1; return a->dircount(&(*file), &(*count)); } long rfsv_rmdir(const char *name) { + if (!a) + return -1; return a->rmdir(name); } @@ -60,48 +80,129 @@ long rfsv_mkdir(const char *file) { } long rfsv_remove(const char *file) { + if (!a) + return -1; return a->remove(file); } long rfsv_fclose(long handle) { + if (!a) + return -1; return a->fclose(handle); } long rfsv_fopen(long attr, const char *file, long *handle) { long ph; - long ret = a->fopen(attr, file, ph); + long ret; + + if (!a) + return -1; + ret = a->fopen(a->opMode(attr), file, ph); *handle = ph; return ret; } long rfsv_fcreate(long attr, const char *file, long *handle) { long ph; - long ret = a->fcreatefile(attr, file, ph); + long ret; + + if (!a) + return -1; + ret = a->fcreatefile(attr, file, ph); *handle = ph; return ret; } -long rfsv_read(char *buf, long offset, long len, long handle) { - long ret = a->fseek(handle, offset, rfsv32::PSI_SEEK_SET); - if (ret >= 0) - ret = a->fread(handle, buf, len); +static long rfsv_opencached(const char *name, long mode) { + long ret; + int retry = 100; + + if (!a) + return -1; + while (((ret = a->fopen(a->opMode(mode), name, a_handle)) + == rfsv::E_PSI_GEN_INUSE) && retry--) + ; + if (ret) + return ret; + a_offset = 0; + a_openmode = mode; + a_filename = strdup(name); return ret; } -long rfsv_write(char *buf, long offset, long len, long handle) { - long ret = a->fseek(handle, offset, rfsv32::PSI_SEEK_SET); - if (ret >= 0) - ret = a->fwrite(handle, buf, len); +static long rfsv_closecached() { + if (!a) + return -1; + if (!a_filename) + return 0; + a->fclose(a_handle); + free(a_filename); + a_filename = 0; + return 0; +} + +long rfsv_read(char *buf, long offset, long len, char *name) { + // FIXME: this might break on RFSV16? + long ret = 0; + + if (!a) + return -1; + if (!a_filename || strcmp(a_filename, name) || a_openmode != rfsv::PSI_O_RDONLY) { + rfsv_closecached(); + if((ret = rfsv_opencached(name, rfsv::PSI_O_RDONLY))) + return ret; + } + if (a_offset != offset) + ret = a->fseek(a_handle, offset, rfsv::PSI_SEEK_SET); + if (ret >= 0) { + a_offset = offset; + ret = a->fread(a_handle, (unsigned char *)buf, len); + if (ret <= 0) + return ret; + a_offset += ret; + } + return ret; +} + +long rfsv_write(char *buf, long offset, long len, char *name) { + // FIXME: this might break on RFSV16? + long ret = 0; + + if (!a) + return -1; + + if (!a_filename || strcmp(a_filename, name) || a_openmode != rfsv::PSI_O_RDWR) { + if ((ret = rfsv_closecached())) + return ret; + if ((ret = rfsv_opencached(name, rfsv::PSI_O_RDWR))) + return ret; + } + if (a_offset != offset) + ret = a->fseek(a_handle, offset, rfsv::PSI_SEEK_SET); + if (ret >= 0) { + a_offset = offset; + ret = a->fwrite(a_handle, (unsigned char *)buf, len); + if (ret <= 0) + return ret; + a_offset += ret; + } return ret; } long rfsv_setmtime(const char *name, long time) { + if (!a) + return -1; return a->fsetmtime(name, time); } long rfsv_setsize(const char *name, long size) { long ph; - long ret = a->fopen(rfsv32::PSI_OMODE_READ_WRITE, name, ph); + long ret; + // FIXME: this might break on RFSV16? + + if (!a) + return -1; + ret = a->fopen(a->opMode(rfsv::PSI_O_RDWR), name, ph); if (!ret) { ret = a->fsetsize(ph, size); a->fclose(ph); @@ -110,10 +211,14 @@ long rfsv_setsize(const char *name, long size) { } long rfsv_setattr(const char *name, long sattr, long dattr) { + if (!a) + return -1; return a->fsetattr(name, dattr, sattr); } long rfsv_getattr(const char *name, long *attr, long *size, long *time) { + if (!a) + return -1; return a->fgeteattr(&(*name), &(*attr), &(*size), &(*time)); } @@ -122,11 +227,15 @@ long rfsv_statdev(char letter) { int devnum = letter - 'A'; char *name; - name = a->devinfo(devnum, &vfree, &vtotal, &vattr, &vuniqueid); + if (!a) + return -1; + name = a->devinfo(devnum, &vfree, &vtotal, &vattr, &vuniqueid); return (name == NULL); } long rfsv_rename(const char *oldname, const char *newname) { + if (!a) + return -1; return a->rename(oldname, newname); } @@ -136,6 +245,8 @@ long rfsv_drivelist(int *cnt, device **dlist) { long ret; int i; + if (!a) + return -1; ret = a->devlist(&devbits); if (ret == 0) for (i = 0; i<26; i++) { @@ -171,6 +282,7 @@ int main(int argc, char**argv) { char *mdir = DDIR; int sockNum = DPORT; int verbose = 0; + int status = 0; for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "-p") && i + 1 < argc) { @@ -187,10 +299,21 @@ int main(int argc, char**argv) { } else usage(); } - signal(SIGPIPE, SIG_IGN); skt = new ppsocket(); - skt->connect(NULL, sockNum); - a = new rfsv32(skt); - return mp_main(verbose, mdir, user); + if (!skt->connect(NULL, sockNum)) { + cerr << "plpnfsd: could not connect to ncpd" << endl; + status = 1; + } else { + rf = new rfsvfactory(skt); + a = rf->create(true); + openlog("plpnfsd", LOG_PID|LOG_CONS, LOG_DAEMON); + if (a != NULL) + syslog(LOG_INFO, "connected, status is %d", status); + else + syslog(LOG_INFO, "could not create rfsv object, connect delayed"); + status = mp_main(verbose, mdir, user); + delete a; + } + exit(status); } diff --git a/plpnfsd/mp_main.c b/plpnfsd/mp_main.c index 23623c6..3c3cab9 100644 --- a/plpnfsd/mp_main.c +++ b/plpnfsd/mp_main.c @@ -46,7 +46,8 @@ fattr root_fattr = {0, 0} }; -#if defined(hpux) || defined(__SVR4) || defined(__sgi) +#if defined(hpux) || defined(__SVR4) || defined(__sgi) +#ifndef sun void usleep(usec) int usec; @@ -57,7 +58,7 @@ int usec; t.tv_usec = (long) (usec % 1000000); select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &t); } - +#endif #endif /* hpux */ int diff --git a/plpnfsd/mp_mount.c b/plpnfsd/mp_mount.c index e607629..f0a82d4 100644 --- a/plpnfsd/mp_mount.c +++ b/plpnfsd/mp_mount.c @@ -589,6 +589,7 @@ mount_and_run(char *dir, void (*proc)(), nfs_fh *root_fh) get_num(cp->inode)->name, dcp->offset); clean_cache(&attrcache); query_cache = 0; /* clear the GETDENTS "cache". */ + rfsv_closecached(); } } } diff --git a/plpnfsd/mp_pfs_ops.c b/plpnfsd/mp_pfs_ops.c index 5bd0a55..669d435 100644 --- a/plpnfsd/mp_pfs_ops.c +++ b/plpnfsd/mp_pfs_ops.c @@ -729,7 +729,6 @@ nfsproc_read_2(struct readargs *ra) fattr *fp; struct cache *cp; struct dcache *dcp; - long phandle; long pattr; long psize; long ptime; @@ -752,30 +751,34 @@ nfsproc_read_2(struct readargs *ra) res.status = NFS_OK; return &res; } - if (rfsv_fopen(1, inode->name, &phandle) != 0) { - res.status = rfsv_isalive() ? NFSERR_NOENT : NO_PSION; - return &res; - } - if (rfsv_read(rop, ra->offset, - ra->count, phandle) < 0) { - rfsv_fclose(phandle); + + if(rfsv_read(rop, ra->offset, + ra->count, inode->name) < 0) { res.status = rfsv_isalive() ? NFSERR_NOENT : NO_PSION; return &res; } - rfsv_fclose(phandle); - rfsv_getattr(inode->name, &pattr, &psize, &ptime); + fp = &res.readres_u.reply.attributes; - pattr2attr(pattr, psize, ptime, fp, (unsigned char *) ra->file.data); - if (cp == 0) - cp = add_cache(&attrcache, inode->inode, fp); + if(!cp) // Problem: if an epoc process is enlarging the file, we wont recognize it + { + rfsv_getattr(inode->name, &pattr, &psize, &ptime); + pattr2attr(pattr, psize, ptime, fp, (unsigned char *) ra->file.data); + cp = add_cache(&attrcache, inode->inode, fp); + } + else + { + *fp = cp->attr; + } + + - len = fp->size - ra->offset; + len = cp->actual_size - ra->offset; if (len > ra->count) len = ra->count; - if (fp->size < ra->offset) + if (cp->actual_size < ra->offset) len = 0; if (debug > 1) - debuglog("Read: filesize %d read %d @ %d\n", fp->size, len, ra->offset); + debuglog("Read: filesize %d read %d @ %d\n", cp->actual_size,len,ra->offset); res.readres_u.reply.data.data_len = len; res.readres_u.reply.data.data_val = (char *) rop; @@ -870,7 +873,6 @@ nfsproc_write_2(writeargs *wa) struct dcache *dcp; fattr *fp; struct attrstat *gres; - long phandle; int len, dlen, doff; if (!inode) { @@ -922,18 +924,11 @@ nfsproc_write_2(writeargs *wa) debuglog("writing off: %d, len: %d, act: %d\n", dcp->offset, dcp->len, cp->actual_size); - if (rfsv_fopen(0x200, inode->name, &phandle) != 0) { - debuglog("write: open failed\n"); - res.status = rfsv_isalive() ? NFSERR_NOSPC : NO_PSION; - return &res; - } - if (rfsv_write(dcp->data, dcp->offset, dcp->len, phandle) != dcp->len) { - rfsv_fclose(phandle); + if (rfsv_write(dcp->data, dcp->offset, dcp->len, inode->name) != dcp->len) { debuglog("write: dump failed\n"); res.status = rfsv_isalive() ? NFSERR_NOSPC : NO_PSION; return &res; } - rfsv_fclose(phandle); dcp->towrite = 0; len = dcp->offset + dcp->len; if (len > cp->actual_size) diff --git a/plpnfsd/rfsv_api.h b/plpnfsd/rfsv_api.h index b1993f9..b63911d 100644 --- a/plpnfsd/rfsv_api.h +++ b/plpnfsd/rfsv_api.h @@ -18,8 +18,8 @@ extern long rfsv_rename(const char *oldname, const char *newname); extern long rfsv_fclose(long handle); extern long rfsv_fopen(long attr, const char *name, long *handle); extern long rfsv_fcreate(long attr, const char *name, long *handle); -extern long rfsv_read(char *buf, long offset, long len, long handle); -extern long rfsv_write(char *buf, long offset, long len, long handle); +extern long rfsv_read(char *buf, long offset, long len, char *name); +extern long rfsv_write(char *buf, long offset, long len, char *name); extern long rfsv_getattr(const char *name, long *attr, long *size, long *time); extern long rfsv_setattr(const char *name, long sattr, long dattr); extern long rfsv_setsize(const char *name, long size); @@ -28,5 +28,6 @@ extern long rfsv_drivelist(int *cnt, device **devlist); extern long rfsv_dircount(const char *name, long *count); extern long rfsv_statdev(char letter); extern long rfsv_isalive(); +extern long rfsv_closecached(void); #endif |