aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--acconfig.h30
-rw-r--r--configure.in84
-rw-r--r--doc/ncpd.man.in6
-rw-r--r--kde2/kpsion/kpsion.cpp71
-rw-r--r--lib/rfsv.cc16
-rw-r--r--lib/rfsv.h7
-rw-r--r--lib/rfsv16.cc19
-rw-r--r--lib/rpcs.h4
-rw-r--r--lib/rpcs32.cc28
-rw-r--r--lib/rpcs32.h4
-rw-r--r--ncpd/channel.cc24
-rw-r--r--ncpd/channel.h7
-rw-r--r--ncpd/link.cc183
-rw-r--r--ncpd/link.h29
-rw-r--r--ncpd/main.cc5
-rw-r--r--ncpd/mp_serial.c5
-rw-r--r--ncpd/ncp.cc126
-rw-r--r--ncpd/ncp.h25
-rw-r--r--ncpd/packet.cc87
-rw-r--r--ncpd/packet.h6
-rw-r--r--ncpd/socketchan.cc44
-rw-r--r--plpbackup/plpbackup.cc521
-rw-r--r--plpftp/ftp.cc12
23 files changed, 1135 insertions, 208 deletions
diff --git a/acconfig.h b/acconfig.h
index eba7710..db3299c 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -12,9 +12,6 @@
/* Define this, if you have libreadline */
#undef HAVE_LIBREADLINE
-/* Define this, if you have libhistory */
-#undef HAVE_LIBHISTORY
-
/* Define if the C++ compiler supports BOOL */
#undef HAVE_BOOL
@@ -39,33 +36,6 @@
/* The package name */
#undef PACKAGE
-/* Define this to your mtab's path */
-#undef MTAB_PATH
-
-/* Define this to your temporary mtab's path */
-#undef MTAB_TMP
-
-/* Define this this if you want to prevent plpnfsd from updating mtab */
-#undef DONT_UPDATE_MTAB
-
-/* Define this to your serial device node */
-#undef DDEV
-
-/* Define this to your serial device speed */
-#undef DSPEED
-
-/* Define this to the TCP port ncpd should listen on */
-#undef DPORT
-
-/* Define this to your default drive on your Psion */
-#undef DDRIVE
-
-/* Define this to your default directory on your Psion */
-#undef DBASEDIR
-
-/* Define this to your default mountpoint for plpnfsd */
-#undef DMOUNTPOINT
-
/* Define this to enable debugging code */
#undef DEBUG
diff --git a/configure.in b/configure.in
index e2cd512..f4e23ad 100644
--- a/configure.in
+++ b/configure.in
@@ -86,7 +86,8 @@ AC_ARG_ENABLE(history,
if test "x$ac_enable_history" = "xyes" ; then
AC_CHECK_LIB(history, add_history,
[
- AC_DEFINE_UNQUOTED(HAVE_LIBHISTORY)
+ AC_DEFINE_UNQUOTED(HAVE_LIBHISTORY,1,
+ [Define this, if you have libhistory])
ac_cv_libhistory=-lhistory
])
fi
@@ -102,28 +103,33 @@ AC_CHECK_LIB(rpcsoc, svcudp_create,,LDFLAGS=$ac_save_LDFLAGS)
dnl checks for mount table - if desired
ac_enable_mnttab=yes
AC_ARG_ENABLE(mnttab,
- [ --disable-mnttab disable mnttab writing [no]],
- if test "$enableval" = "no" ; then
- AC_MSG_RESULT([support for mnttab disabled])
- ac_enable_mnttab=no
- fi
+ [ --disable-mnttab disable mnttab writing [no]],
+ if test "$enableval" = "no" ; then
+ AC_MSG_RESULT([support for mnttab disabled])
+ ac_enable_mnttab=no
+ fi
)
if test "x$ac_enable_mnttab" = "xyes" ; then
- AC_MSG_CHECKING(for mount table)
- PLP_FIND_FILE(/etc/mnttab /etc/mtab, MTAB)
- AC_MSG_RESULT($MTAB)
- test "$MTAB" = "NO" && AC_DEFINE_UNQUOTED(DONT_UPDATE_MTAB)
- AC_DEFINE_UNQUOTED(MTAB_PATH,"$MTAB")
- case "$target_alias" in
- *linux*)
- AC_DEFINE_UNQUOTED(MTAB_TMP,"${MTAB}~")
- ;;
- *)
- AC_DEFINE_UNQUOTED(MTAB_TMP,"${MTAB}.plpnfsd")
- ;;
- esac
-else
- AC_DEFINE_UNQUOTED(DONT_UPDATE_MTAB)
+ AC_MSG_CHECKING(for mount table)
+ PLP_FIND_FILE(/etc/mnttab /etc/mtab, MTAB)
+ AC_MSG_RESULT($MTAB)
+ if test "$MTAB" = "NO" ; then
+ AC_DEFINE_UNQUOTED(DONT_UPDATE_MTAB,1,
+ [Define this this if you want to prevent plpnfsd from updating mtab])
+ else
+ AC_DEFINE_UNQUOTED(MTAB_PATH,"$MTAB",
+ [Define this to your mtab's path])
+ ac_cv_mtab_tmp="${MTAB}~"
+ case "$target_alias" in
+ *linux*)
+ ;;
+ *)
+ ac_cv_mtab_tmp="${MTAB}.plpnfsd"
+ ;;
+ esac
+ AC_DEFINE_UNQUOTED(MTAB_TMP,"${ac_cv_mtab_tmp}",
+ [Define this to your temporary mtab's path])
+ fi
fi
dnl Check, if bot time.h and sys/time.h may be included
@@ -158,19 +164,29 @@ AC_ARG_WITH(serial,
test "$DDEV" = "NO" && AC_MSG_ERROR(NO serial lines. Use --with-serial.)
]
)
-AC_DEFINE_UNQUOTED(DDEV,"$DDEV")
+AC_DEFINE_UNQUOTED(DDEV,"$DDEV",[Define this to your serial device node])
AC_SUBST(DDEV)
AC_ARG_WITH(speed,
- [ --with-speed=SPEED override default serial speed [115200]],
- [ DSPEED="$withval"
- AC_MSG_RESULT(Overriding serial speed: $DSPEED) ],
- [ DSPEED=115200
- AC_MSG_RESULT(Using default serial speed: $DSPEED)
+ [ --with-speed=SPEED override default serial speed [auto]],
+ [ if "$withval" = "auto" ; then
+ DSNAME=auto
+ DSPEED=-1
+ else
+ DSPEED="$withval"
+ DSNAME="$withval"
+ fi
+ AC_MSG_RESULT(Overriding serial speed: $DSNAME) ],
+ [ DSPEED=-1
+ DSNAME=auto
+ AC_MSG_RESULT(Using default serial speed: auto)
]
)
-AC_DEFINE_UNQUOTED(DSPEED,$DSPEED)
+AC_DEFINE_UNQUOTED(DSPEED,$DSPEED,[Define this to your serial device speed])
+AC_DEFINE_UNQUOTED(DSNAME,$DSNAME,
+ [Define this to your serial device speed alias])
AC_SUBST(DSPEED)
+AC_SUBST(DSNAME)
AC_ARG_WITH(port,
[ --with-port=PORT override default port [7501]],
@@ -180,7 +196,8 @@ AC_ARG_WITH(port,
AC_MSG_RESULT(Using default port: $DPORT)
]
)
-AC_DEFINE_UNQUOTED(DPORT,$DPORT)
+AC_DEFINE_UNQUOTED(DPORT,$DPORT,
+ [Define this to the TCP port ncpd should listen on])
AC_SUBST(DPORT)
AC_ARG_WITH(drive,
@@ -191,7 +208,8 @@ AC_ARG_WITH(drive,
AC_MSG_RESULT(Using default Psion drive: $DDRIVE)
]
)
-AC_DEFINE_UNQUOTED(DDRIVE,"$DDRIVE")
+AC_DEFINE_UNQUOTED(DDRIVE,"$DDRIVE",
+ [Define this to your default drive on your Psion])
AC_ARG_WITH(basedir,
[ --with-basedir=DIR override default Psion directory [\\\\]],
@@ -201,7 +219,8 @@ AC_ARG_WITH(basedir,
AC_MSG_RESULT(Using default Psion directory: $DBASEDIR)
]
)
-AC_DEFINE_UNQUOTED(DBASEDIR,"$DBASEDIR")
+AC_DEFINE_UNQUOTED(DBASEDIR,"$DBASEDIR",
+ [Define this to your default directory on your Psion])
AC_ARG_WITH(mountdir,
[ --with-mountdir=DIR override default mount point [/mnt/psion]],
@@ -211,7 +230,8 @@ AC_ARG_WITH(mountdir,
AC_MSG_RESULT(Using default mount point: $DMOUNTPOINT)
]
)
-AC_DEFINE_UNQUOTED(DMOUNTPOINT,"$DMOUNTPOINT")
+AC_DEFINE_UNQUOTED(DMOUNTPOINT,"$DMOUNTPOINT",
+ [Define this to your default mountpoint for plpnfsd])
AC_SUBST(DMOUNTPOINT)
test "x$prefix" = xNONE && prefix="$ac_default_prefix"
eval PKGDATA="${datadir}/${PACKAGE}"
diff --git a/doc/ncpd.man.in b/doc/ncpd.man.in
index d14779b..03ffda9 100644
--- a/doc/ncpd.man.in
+++ b/doc/ncpd.man.in
@@ -91,8 +91,10 @@ Specify the serial device to use to connect to the Psion - this defaults to
@DDEV@
.TP
.BI "\-b, --baudrate=" baudrate
-Specify the baud rate to use for the serial connection - this defaults to
-@DSPEED@ baud.
+Specify the baud rate to use for the serial connection. If the word
+.B auto
+is specified, ncpd cycles through baudrates of 115200, 57600, 38400, 19200
+and 9600 baud. Default setting is @DSNAME@.
.SH SEE ALSO
plpftp(1), plpnfsd(8)
diff --git a/kde2/kpsion/kpsion.cpp b/kde2/kpsion/kpsion.cpp
index e6a8d4d..6ba36a7 100644
--- a/kde2/kpsion/kpsion.cpp
+++ b/kde2/kpsion/kpsion.cpp
@@ -864,37 +864,49 @@ doBackup() {
u_int32_t handle;
kapp->processEvents();
- res = plpRfsv->fopen(plpRfsv->opMode(rfsv::PSI_O_RDONLY), fn,
- handle);
- if (res != rfsv::E_PSI_GEN_NONE) {
- if (KMessageBox::warningYesNo(this, i18n("<QT>Could not open<BR/><B>%1</B></QT>").arg(fn)) == KMessageBox::No) {
- badBackup = true;
- break;
- } else {
- e.setName("!");
- continue;
- }
- }
- unsigned char *buff = new unsigned char[RFSV_SENDLEN];
- u_int32_t len;
+ bool tryLoop = true;
do {
- if ((res = plpRfsv->fread(handle, buff, RFSV_SENDLEN, len)) ==
- rfsv::E_PSI_GEN_NONE) {
- os.writeRawBytes((char *)buff, len);
- updateProgress(len);
+ res = plpRfsv->fopen(plpRfsv->opMode(rfsv::PSI_O_RDONLY), fn,
+ handle);
+ if (res == rfsv::E_PSI_GEN_NONE) {
+ unsigned char *buff = new unsigned char[RFSV_SENDLEN];
+ u_int32_t len;
+ do {
+ if ((res = plpRfsv->fread(handle, buff, RFSV_SENDLEN,
+ len)) == rfsv::E_PSI_GEN_NONE) {
+ os.writeRawBytes((char *)buff, len);
+ updateProgress(len);
+ }
+ } while ((len > 0) && (res == rfsv::E_PSI_GEN_NONE));
+ delete[]buff;
+ plpRfsv->fclose(handle);
}
- } while ((len > 0) && (res == rfsv::E_PSI_GEN_NONE));
- delete[]buff;
- plpRfsv->fclose(handle);
- if (res != rfsv::E_PSI_GEN_NONE) {
- if (KMessageBox::warningYesNo(this, i18n("<QT>Could not read<BR/><B>%1</B></QT>").arg(fn)) == KMessageBox::No) {
- badBackup = true;
- break;
+ if (res != rfsv::E_PSI_GEN_NONE) {
+ switch (KMessageBox::warningYesNoCancel(
+ this, i18n(
+ "<QT>Could not backup<BR/><B>%1</B><BR/>"
+ "<FONT COLOR=RED>%2</FONT><BR/></QT>"
+ ).arg(fn).arg((const char *)res),
+ QString::null, i18n("Retry"), i18n("Ignore"))) {
+ case KMessageBox::Cancel:
+ badBackup = true;
+ tryLoop = false;
+ break;
+ case KMessageBox::No:
+ e.setName("!");
+ tryLoop = false;
+ break;
+ case KMessageBox::Yes:
+ break;
+ }
} else {
- e.setName("!");
- continue;
+ tryLoop = false;
}
- }
+ } while (tryLoop);
+ if (badBackup)
+ break;
+ if (res != rfsv::E_PSI_GEN_NONE)
+ continue;
backupTgz->writeFile(unixname, "root", "root", ba.size(), ba.data());
}
@@ -915,7 +927,7 @@ doBackup() {
kapp->processEvents();
res = plpRfsv->fsetattr(fn, 0, rfsv::PSI_A_ARCHIVE);
if (res != rfsv::E_PSI_GEN_NONE) {
- if (KMessageBox::warningYesNo(this, i18n("<QT>Could not set attributes of<BR/><B>%1</B></QT>").arg(fn)) == KMessageBox::No) {
+ if (KMessageBox::warningYesNo(this, i18n("<QT>Could not set attributes of<BR/><B>%1</B><BR/><FONT COLOR=red>%2</FONT><BR/>Continue?</QT>").arg(fn)) == KMessageBox::No) {
break;
}
}
@@ -998,7 +1010,6 @@ removeOldBackups(QStringList &drives) {
QFileInfoListIterator it(*fil);
QFileInfo *fi;
ArchList alist;
- Barchive *a;
// Build a list of full-backups sorted by date
while ((fi = it.current())) {
@@ -1637,7 +1648,7 @@ killSave() {
"<QT>Could not stop all processes.<BR/>"
"Please stop running programs manually on the Psion, "
"then klick <B>Ok</B>."));
- time_t tstart = time(0) + 5;
+ tstart = time(0) + 5;
}
}
return;
diff --git a/lib/rfsv.cc b/lib/rfsv.cc
index 25bf91c..310d7c4 100644
--- a/lib/rfsv.cc
+++ b/lib/rfsv.cc
@@ -167,6 +167,22 @@ attr2String(const u_int32_t attr)
return tmp;
}
+int rfsv::
+getSpeed()
+{
+ bufferStore a;
+ a.addStringT("NCP$GSPD");
+ if (!skt->sendBufferStore(a))
+ return -1;
+ if (skt->getBufferStore(a) != 1)
+ return -1;
+ if (a.getLen() != 5)
+ return -1;
+ if (a.getByte(0) != E_PSI_GEN_NONE)
+ return -1;
+ return a.getDWord(1);
+}
+
/*
* Local variables:
* c-basic-offset: 4
diff --git a/lib/rfsv.h b/lib/rfsv.h
index 2a445ef..312c1b8 100644
--- a/lib/rfsv.h
+++ b/lib/rfsv.h
@@ -600,6 +600,13 @@ public:
*/
static string convertSlash(const string &name);
+ /**
+ * Retrieve speed of serial link.
+ *
+ * @returns The speed of the serial link in baud or -1 on error.
+ */
+ int getSpeed();
+
protected:
/**
* Retrieves the PLP protocol name. Mainly internal use.
diff --git a/lib/rfsv16.cc b/lib/rfsv16.cc
index 2474060..773a5c1 100644
--- a/lib/rfsv16.cc
+++ b/lib/rfsv16.cc
@@ -222,10 +222,21 @@ fgetmtime(const char * const name, PsiTime &mtime)
Enum<rfsv::errs> rfsv16::
fsetmtime(const char *name, PsiTime 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;
+ // According to Alexander's protocol doc, SFDATE sets the modification
+ // time - and as far as I can see SIBO only keeps a modification
+ // time. So call SFDATE here.
+ bufferStore a;
+ string realName = convertSlash(name);
+ a.addDWord(mtime.getTime());
+ a.addStringT(realName.c_str());
+ // and this needs sending in the length word.
+ if (!sendCommand(SFDATE, a))
+ return E_PSI_FILE_DISC;
+
+ Enum<rfsv::errs> res = getResponse(a);
+ if (res != E_PSI_GEN_NONE)
+ cerr << "fsetmtime: Error " << res << " on file " << name << endl;
+ return res;
}
Enum<rfsv::errs> rfsv16::
diff --git a/lib/rpcs.h b/lib/rpcs.h
index 2b40fa9..5a64013 100644
--- a/lib/rpcs.h
+++ b/lib/rpcs.h
@@ -338,8 +338,8 @@ public:
*/
virtual Enum<rfsv::errs> getMachineInfo(machineInfo &) { return rfsv::E_PSI_NOT_SIBO;}
virtual Enum<rfsv::errs> closeHandle(int) { return rfsv::E_PSI_NOT_SIBO;}
- virtual Enum<rfsv::errs> regOpenIter(void) { return rfsv::E_PSI_NOT_SIBO;}
- virtual Enum<rfsv::errs> regReadIter(void) { return rfsv::E_PSI_NOT_SIBO;}
+ virtual Enum<rfsv::errs> regOpenIter(u_int32_t, char *, u_int16_t &) { return rfsv::E_PSI_NOT_SIBO;}
+ virtual Enum<rfsv::errs> regReadIter(u_int16_t) { return rfsv::E_PSI_NOT_SIBO;}
virtual Enum<rfsv::errs> regWrite(void) { return rfsv::E_PSI_NOT_SIBO;}
virtual Enum<rfsv::errs> regRead(void) { return rfsv::E_PSI_NOT_SIBO;}
virtual Enum<rfsv::errs> regDelete(void) { return rfsv::E_PSI_NOT_SIBO;}
diff --git a/lib/rpcs32.cc b/lib/rpcs32.cc
index 38d7933..ebb4f9c 100644
--- a/lib/rpcs32.cc
+++ b/lib/rpcs32.cc
@@ -169,18 +169,38 @@ getMachineInfo(machineInfo &mi)
static unsigned long hhh;
Enum<rfsv::errs> rpcs32::
-regOpenIter(void)
+regOpenIter(u_int32_t uid, char *match, u_int16_t &handle)
{
bufferStore a;
Enum<rfsv::errs> res;
- a.addStringT("HKLM\\");
+ cout << "Oiter" << endl;
+ a.addDWord(uid);
+ a.addDWord(strlen(match));
+ a.addStringT(match);
if (!sendCommand(rpcs::REG_OPEN_ITER, a))
return rfsv::E_PSI_FILE_DISC;
res = getResponse(a, true);
cout << "ro: r=" << res << " a=" << a << endl;
- if (a.getLen() > 0)
- hhh = a.getDWord(0);
+ if (a.getLen() == 2)
+ handle = a.getWord(0);
+ return rfsv::E_PSI_GEN_NONE;
+}
+
+Enum<rfsv::errs> rpcs32::
+regReadIter(u_int16_t handle)
+{
+ bufferStore a;
+ Enum<rfsv::errs> res;
+
+ cout << "Riter" << endl;
+ a.addWord(handle);
+ if (!sendCommand(rpcs::REG_READ_ITER, a))
+ return rfsv::E_PSI_FILE_DISC;
+ res = getResponse(a, true);
+ cout << "ro: r=" << res << " a=" << a << endl;
+ if ((a.getLen() == 3) && (a.getByte(2) == 0xff))
+ return rfsv::E_PSI_FILE_EOF;
return rfsv::E_PSI_GEN_NONE;
}
diff --git a/lib/rpcs32.h b/lib/rpcs32.h
index 0256b66..70644da 100644
--- a/lib/rpcs32.h
+++ b/lib/rpcs32.h
@@ -48,9 +48,9 @@ class rpcs32 : public rpcs {
#if 0
Enum<rfsv::errs> closeHandle(int);
#endif
- Enum<rfsv::errs> regOpenIter(void);
+ Enum<rfsv::errs> regOpenIter(u_int32_t uid, char *match, u_int16_t &handle);
+ Enum<rfsv::errs> regReadIter(u_int16_t handle);
#if 0
- Enum<rfsv::errs> regReadIter(void);
Enum<rfsv::errs> regWrite(void);
Enum<rfsv::errs> regRead(void);
Enum<rfsv::errs> regDelete(void);
diff --git a/ncpd/channel.cc b/ncpd/channel.cc
index e51b903..d3189e4 100644
--- a/ncpd/channel.cc
+++ b/ncpd/channel.cc
@@ -87,6 +87,30 @@ ncpDisconnect()
ncpController->disconnect(ncpChannel);
}
+PcServer *channel::
+ncpFindPcServer(const char *name)
+{
+ return ncpController->findPcServer(name);
+}
+
+void channel::
+ncpRegisterPcServer(ppsocket *skt, const char *name)
+{
+ ncpController->registerPcServer(skt, name);
+}
+
+void channel::
+ncpUnregisterPcServer(PcServer *server)
+{
+ ncpController->unregisterPcServer(server);
+}
+
+int channel::
+ncpGetSpeed()
+{
+ return ncpController->getSpeed();
+}
+
short int channel::
ncpProtocolVersion()
{
diff --git a/ncpd/channel.h b/ncpd/channel.h
index 585ef31..e9bf3ea 100644
--- a/ncpd/channel.h
+++ b/ncpd/channel.h
@@ -31,6 +31,8 @@
class ncp;
class bufferStore;
+class PcServer;
+class ppsocket;
class channel {
public:
@@ -61,6 +63,11 @@ public:
virtual bool terminate(); // Mainloop will terminate this class if true
void terminateWhenAsked();
+ PcServer *ncpFindPcServer(const char *name);
+ void ncpRegisterPcServer(ppsocket *skt, const char *name);
+ void ncpUnregisterPcServer(PcServer *server);
+ int ncpGetSpeed();
+
protected:
short int verbose;
const char *connectName;
diff --git a/ncpd/link.cc b/ncpd/link.cc
index a52e3ef..025e131 100644
--- a/ncpd/link.cc
+++ b/ncpd/link.cc
@@ -44,16 +44,21 @@ extern "C" {
Link *l = (Link *)arg;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while (1) {
- usleep(l->retransTimeout * 500);
+ usleep(l->retransTimeout() * 500);
l->retransmit();
}
}
};
+ENUM_DEFINITION(Link::link_type, Link::LINK_TYPE_UNKNOWN) {
+ stringRep.add(Link::LINK_TYPE_UNKNOWN, N_("Unknown"));
+ stringRep.add(Link::LINK_TYPE_SIBO, N_("SIBO"));
+ stringRep.add(Link::LINK_TYPE_EPOC, N_("EPOC"));
+}
+
Link::Link(const char *fname, int baud, ncp *_ncp, unsigned short _verbose)
+ : p(0)
{
- p = new packet(fname, baud, this, _verbose);
- retransTimeout = ((unsigned long)baud * 1000 / 13200) + 200;
theNCP = _ncp;
verbose = _verbose;
txSequence = 1;
@@ -61,18 +66,20 @@ Link::Link(const char *fname, int baud, ncp *_ncp, unsigned short _verbose)
failed = false;
seqMask = 7;
maxOutstanding = 1;
+ linkType = LINK_TYPE_UNKNOWN;
for (int i = 0; i < 256; i++)
xoff[i] = false;
- // generate magic number for sendCon()
+ // generate magic number for sendReqCon()
srandom(time(NULL));
conMagic = random();
+ p = new packet(fname, baud, this, _verbose);
+
pthread_mutex_init(&queueMutex, NULL);
pthread_create(&checkthread, NULL, expire_check, this);
// submit a link request
- bufferStore blank;
- transmit(blank);
+ sendReqReq();
}
Link::~Link()
@@ -83,22 +90,27 @@ Link::~Link()
delete p;
}
+unsigned long Link::
+retransTimeout()
+{
+ return ((unsigned long)getSpeed() * 1000 / 13200) + 200;
+}
+
void Link::
reset() {
+ p->reset();
txSequence = 1;
rxSequence = -1;
failed = false;
-
- pthread_mutex_lock(&queueMutex);
- ackWaitQueue.clear();
- holdQueue.clear();
- pthread_mutex_unlock(&queueMutex);
+ seqMask = 7;
+ maxOutstanding = 1;
+ linkType = LINK_TYPE_UNKNOWN;
+ purgeAllQueues();
for (int i = 0; i < 256; i++)
xoff[i] = false;
// submit a link request
- bufferStore blank;
- transmit(blank);
+ sendReqReq();
}
unsigned short Link::
@@ -124,6 +136,15 @@ send(const bufferStore & buff)
}
void Link::
+purgeAllQueues()
+{
+ pthread_mutex_lock(&queueMutex);
+ ackWaitQueue.clear();
+ holdQueue.clear();
+ pthread_mutex_unlock(&queueMutex);
+}
+
+void Link::
purgeQueue(int channel)
{
pthread_mutex_lock(&queueMutex);
@@ -161,7 +182,7 @@ sendAck(int seq)
}
void Link::
-sendCon()
+sendReqCon()
{
if (hasFailed())
return;
@@ -182,8 +203,44 @@ sendCon()
}
void Link::
+sendReqReq()
+{
+ if (hasFailed())
+ return;
+ bufferStore tmp;
+ if (verbose & LNK_DEBUG_LOG)
+ cout << "Link: >> con seq=1" << endl;
+ tmp.addByte(0x21);
+ ackWaitQueueElement e;
+ e.seq = 0; // expected response is Ack with seq=0 or ReqCon
+ gettimeofday(&e.stamp, NULL);
+ e.data = tmp;
+ e.txcount = 4;
+ pthread_mutex_lock(&queueMutex);
+ ackWaitQueue.push_back(e);
+ pthread_mutex_unlock(&queueMutex);
+ p->send(tmp);
+}
+
+void Link::
+sendReq()
+{
+ if (hasFailed())
+ return;
+ bufferStore tmp;
+ if (verbose & LNK_DEBUG_LOG)
+ cout << "Link: >> con seq=1" << endl;
+ tmp.addByte(0x20);
+ // No Ack expected for this, so no new entry in ackWaitQueue
+ p->send(tmp);
+}
+
+void Link::
receive(bufferStore buff)
{
+ if (!p)
+ return;
+
vector<ackWaitQueueElement>::iterator i;
bool ackFound;
bool conFound;
@@ -267,17 +324,58 @@ receive(bufferStore buff)
}
pthread_mutex_unlock(&queueMutex);
if (ackFound) {
+ if ((linkType == LINK_TYPE_UNKNOWN) && (seq == 0)) {
+ // If the remote device runs SIBO protocol, this ACK
+ // should be 0 (the Ack on our ReqReq request, which is
+ // treated as a normal Req by the SIBO machine.
+ failed = false;
+ linkType = LINK_TYPE_SIBO;
+ seqMask = 7;
+ maxOutstanding = 1;
+ rxSequence = 0;
+ txSequence = 1;
+ purgeAllQueues();
+ if (verbose & LNK_DEBUG_LOG)
+ cout << "Link: 1-linkType set to " << linkType << endl;
+ }
// Older packets implicitely ack'ed
multiAck(refstamp);
// Transmit waiting packets
transmitWaitQueue();
} else {
if (verbose & LNK_DEBUG_LOG) {
- cout << "Link: << UNMATCHED ack seq=" << seq ;
+ cout << "Link: << UNMATCHED ack seq=" << seq;
if (verbose & LNK_DEBUG_DUMP)
cout << " " << buff;
cout << endl;
}
+ // If packet with seq+1 is in ackWaitQueue, resend it immediately
+ // (Receiving an ack for a packet not on our wait queue is a
+ // hint by the Psion about which was the last packet it
+ // received successfully.)
+ pthread_mutex_lock(&queueMutex);
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ for (i = ackWaitQueue.begin(); i != ackWaitQueue.end(); i++)
+ if (i->seq == seq+1) {
+ if (i->txcount-- == 0) {
+ // timeout, remove packet
+ if (verbose & LNK_DEBUG_LOG)
+ cout << "Link: >> TRANSMIT timeout seq=" <<
+ i->seq << endl;
+ ackWaitQueue.erase(i);
+ i--;
+ } else {
+ // retransmit it
+ i->stamp = now;
+ if (verbose & LNK_DEBUG_LOG)
+ cout << "Link: >> RETRANSMIT seq=" << i->seq
+ << endl;
+ p->send(i->data);
+ }
+ break;
+ }
+ pthread_mutex_unlock(&queueMutex);
}
break;
@@ -288,10 +386,13 @@ receive(bufferStore buff)
// May be a link confirm packet (EPOC)
pthread_mutex_lock(&queueMutex);
for (i = ackWaitQueue.begin(); i != ackWaitQueue.end(); i++)
- if ((i->seq > 0) && (i->seq < 4) &&
- (i->data.getByte(0) & 0xf0) == 0x20) {
+ if ((i->seq == 0) && (i->data.getByte(0) & 0xf0) == 0x20) {
ackWaitQueue.erase(i);
+ linkType = LINK_TYPE_EPOC;
+ if (verbose & LNK_DEBUG_LOG)
+ cout << "Link: 2-linkType set to " << linkType << endl;
conFound = true;
+ failed = false;
// EPOC can handle extended sequence numbers
seqMask = 0x7ff;
// EPOC can handle up to 8 unacknowledged packets
@@ -310,6 +411,7 @@ receive(bufferStore buff)
if (conFound) {
rxSequence = 0;
txSequence = 1;
+ purgeAllQueues();
sendAck(rxSequence);
} else {
if (verbose & LNK_DEBUG_LOG) {
@@ -320,14 +422,30 @@ receive(bufferStore buff)
}
rxSequence = txSequence = 0;
if (seq > 0) {
+ linkType = LINK_TYPE_EPOC;
+ if (verbose & LNK_DEBUG_LOG)
+ cout << "Link: 3-linkType set to " << linkType << endl;
// EPOC can handle extended sequence numbers
seqMask = 0x7ff;
// EPOC can handle up to 8 unacknowledged packets
maxOutstanding = 8;
p->setEpoc(true);
- sendCon();
- } else
+ purgeAllQueues();
+ failed = false;
+ sendReqCon();
+ } else {
+ // SIBO
+ linkType = LINK_TYPE_SIBO;
+ failed = false;
+ seqMask = 7;
+ maxOutstanding = 1;
+ if (verbose & LNK_DEBUG_LOG)
+ cout << "Link: 4-linkType set to " << linkType << endl;
+ rxSequence = 0;
+ txSequence = 1; // Our ReqReq was seq 0
+ purgeAllQueues();
sendAck(rxSequence);
+ }
}
break;
@@ -481,10 +599,7 @@ retransmit()
{
if (hasFailed()) {
- pthread_mutex_lock(&queueMutex);
- ackWaitQueue.clear();
- holdQueue.clear();
- pthread_mutex_unlock(&queueMutex);
+ purgeAllQueues();
return;
}
@@ -493,7 +608,7 @@ retransmit()
struct timeval now;
gettimeofday(&now, NULL);
struct timeval expired = now;
- timesub(&expired, retransTimeout);
+ timesub(&expired, retransTimeout());
for (i = ackWaitQueue.begin(); i != ackWaitQueue.end(); i++)
if (olderthan(i->stamp, expired)) {
if (i->txcount-- == 0) {
@@ -501,6 +616,7 @@ retransmit()
if (verbose & LNK_DEBUG_LOG)
cout << "Link: >> TRANSMIT timeout seq=" << i->seq << endl;
ackWaitQueue.erase(i);
+ failed = true;
i--;
} else {
// retransmit it
@@ -528,10 +644,27 @@ stuffToSend()
bool Link::
hasFailed()
{
- failed |= p->linkFailed();
+ bool lfailed = p->linkFailed();
+ if (failed || lfailed) {
+ if (verbose & LNK_DEBUG_LOG)
+ cout << "Link: hasFailed: " << failed << ", " << lfailed << endl;
+ }
+ failed |= lfailed;
return failed;
}
+Enum<Link::link_type> Link::
+getLinkType()
+{
+ return linkType;
+}
+
+int Link::
+getSpeed()
+{
+ return p->getSpeed();
+}
+
/*
* Local variables:
* c-basic-offset: 4
diff --git a/ncpd/link.h b/ncpd/link.h
index 81732b6..25cd280 100644
--- a/ncpd/link.h
+++ b/ncpd/link.h
@@ -32,6 +32,7 @@
#include "bufferstore.h"
#include "bufferarray.h"
+#include "Enum.h"
#include <vector>
#define LNK_DEBUG_LOG 4
@@ -70,6 +71,12 @@ extern "C" {
class Link {
public:
+ enum link_type {
+ LINK_TYPE_UNKNOWN = 0,
+ LINK_TYPE_SIBO = 1,
+ LINK_TYPE_EPOC = 2,
+ };
+
/**
* Construct a new link instance.
*
@@ -141,6 +148,20 @@ public:
*/
unsigned short getVerbose();
+ /**
+ * Get the current link type.
+ *
+ * @returns One of LINK_TYPE_... values.
+ */
+ Enum<link_type> getLinkType();
+
+ /**
+ * Get current speed of the serial device
+ *
+ * @returns The current speed in baud.
+ */
+ int getSpeed();
+
private:
friend class packet;
friend void * expire_check(void *);
@@ -148,11 +169,15 @@ private:
void receive(bufferStore buf);
void transmit(bufferStore buf);
void sendAck(int seq);
- void sendCon();
+ void sendReqReq();
+ void sendReqCon();
+ void sendReq();
void multiAck(struct timeval);
void retransmit();
void transmitHoldQueue(int channel);
void transmitWaitQueue();
+ void purgeAllQueues();
+ unsigned long retransTimeout();
pthread_t checkthread;
pthread_mutex_t queueMutex;
@@ -163,10 +188,10 @@ private:
int rxSequence;
int seqMask;
int maxOutstanding;
- unsigned long retransTimeout;
unsigned long conMagic;
unsigned short verbose;
bool failed;
+ Enum<link_type> linkType;
vector<ackWaitQueueElement> ackWaitQueue;
vector<bufferStore> holdQueue;
diff --git a/ncpd/main.cc b/ncpd/main.cc
index f1f7f14..4771744 100644
--- a/ncpd/main.cc
+++ b/ncpd/main.cc
@@ -288,7 +288,10 @@ main(int argc, char **argv)
autoexit = true;
break;
case 'b':
- baudRate = atoi(optarg);
+ if (!strcmp(optarg, "auto"))
+ baudRate = -1;
+ else
+ baudRate = atoi(optarg);
break;
case 's':
serialDevice = optarg;
diff --git a/ncpd/mp_serial.c b/ncpd/mp_serial.c
index 7f6a792..7483a3e 100644
--- a/ncpd/mp_serial.c
+++ b/ncpd/mp_serial.c
@@ -131,7 +131,7 @@ init_serial(const char *dev, int speed, int debug)
perror("seteuid");
exit(1);
}
- if ((fd = open(dev, O_RDWR /*FRITZTEST | O_NDELAY */ | O_NOCTTY, 0)) < 0) {
+ if ((fd = open(dev, O_RDWR | O_NOCTTY, 0)) < 0) {
perror(dev);
exit(1);
}
@@ -184,6 +184,9 @@ ser_exit(int fd)
{
struct termios ti;
+#ifdef TIOCNXCL
+ ioctl(fd, TIOCNXCL, (char *) 0);
+#endif
if (tcgetattr(fd, &ti) < 0)
perror("tcgetattr");
ti.c_cflag &= ~CRTSCTS;
diff --git a/ncpd/ncp.cc b/ncpd/ncp.cc
index 76f4d63..f20ca75 100644
--- a/ncpd/ncp.cc
+++ b/ncpd/ncp.cc
@@ -31,9 +31,10 @@
#include "ncp.h"
#include "linkchan.h"
-#include <bufferstore.h>
#include "link.h"
+#include <bufferstore.h>
#include <bufferarray.h>
+#include <rfsv.h>
#define MAX_CHANNELS_PSION 256
#define MAX_CHANNELS_SIBO 8
@@ -54,6 +55,7 @@ ncp::ncp(const char *fname, int baud, unsigned short _verbose)
// until detected on receipt of INFO we use these.
maxChannels = MAX_CHANNELS_SIBO;
protocolVersion = PV_SERIES_5;
+ lChan = NULL;
// init channels
for (int i = 0; i < MAX_CHANNELS_PSION; i++)
@@ -94,6 +96,8 @@ reset() {
channelPtr[i] = NULL;
}
failed = false;
+ if (lChan)
+ delete(lChan);
lChan = NULL;
protocolVersion = PV_SERIES_5; // until detected on receipt of INFO
l->reset();
@@ -158,6 +162,35 @@ controlChannel(int chan, enum interControllerMessageType t, bufferStore & comman
l->send(open);
}
+PcServer *ncp::
+findPcServer(const char *name)
+{
+ if (name) {
+ vector<PcServer>::iterator i;
+ for (i = pcServers.begin(); i != pcServers.end(); i++)
+ if (i->getName() == name)
+ return i;
+ }
+ return NULL;
+}
+
+void ncp::
+registerPcServer(ppsocket *skt, const char *name) {
+ pcServers.push_back(PcServer(skt, name));
+}
+
+void ncp::
+unregisterPcServer(PcServer *server) {
+ if (server) {
+ vector<PcServer>::iterator i;
+ for (i = pcServers.begin(); i != pcServers.end(); i++)
+ if (i == server) {
+ pcServers.erase(i);
+ return;
+ }
+ }
+}
+
void ncp::
decodeControlMessage(bufferStore & buff)
{
@@ -169,6 +202,7 @@ decodeControlMessage(bufferStore & buff)
cout << "ncp: << " << ctrlMsgName(imt) << " " << remoteChan;
bufferStore b;
+ int localChan;
switch (imt) {
case NCON_MSG_CONNECT_TO_SERVER:
@@ -178,33 +212,51 @@ decodeControlMessage(bufferStore & buff)
cout << endl;
}
- int localChan;
-
- // Ack with connect response
- localChan = getFirstUnusedChan();
- b.addByte(remoteChan);
- b.addByte(0);
- 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...
-
+ failed = false;
if (!strcmp(buff.getString(0), "LINK.*")) {
if (lChan)
- failed = true;
+ localChan = lChan->getNcpChannel();
+ else
+ localChan = getFirstUnusedChan();
+
+ // Ack with connect response
+ b.addByte(remoteChan);
+ b.addByte(0);
+ controlChannel(localChan, NCON_MSG_CONNECT_RESPONSE, b);
if (verbose & NCP_DEBUG_LOG)
cout << "ncp: Link UP" << endl;
- channelPtr[localChan] = lChan = new linkChan(this, localChan);
- lChan->setVerbose(verbose);
+ // Create linkchan if it does not yet exist
+ if (!lChan) {
+ if (verbose & NCP_DEBUG_LOG)
+ cout << "ncp: new passive linkChan" << endl;
+ channelPtr[localChan] =
+ lChan = new linkChan(this, localChan);
+ lChan->setVerbose(verbose);
+ }
lChan->ncpConnectAck();
} else {
- if (verbose & NCP_DEBUG_LOG)
- cout << "ncp: REJECT connect" << endl;
- bufferStore b;
+ PcServer *s = findPcServer(buff.getString(0));
+ bool ok = false;
+
+ if (s) {
+ localChan = getFirstUnusedChan();
+ ok = s->clientConnect(localChan, remoteChan);
+ if (!ok)
+ // release channel ptr
+ channelPtr[localChan] = NULL;
+ }
b.addByte(remoteChan);
- controlChannel(0, NCON_MSG_CHANNEL_DISCONNECT, b);
+ if (ok) {
+ b.addByte(rfsv::E_PSI_GEN_NONE);
+ if (verbose & NCP_DEBUG_LOG)
+ cout << "ncp: ACCEPT client connect" << endl;
+ } else {
+ localChan = 0;
+ b.addByte(rfsv::E_PSI_FILE_NXIST);
+ if (verbose & NCP_DEBUG_LOG)
+ cout << "ncp: REJECT client connect" << endl;
+ }
+ controlChannel(localChan, NCON_MSG_CONNECT_RESPONSE, b);
}
break;
@@ -212,6 +264,7 @@ decodeControlMessage(bufferStore & buff)
int forChan;
+ failed = false;
forChan = buff.getByte(0);
if (verbose & NCP_DEBUG_LOG)
cout << " ch=" << forChan << " stat=";
@@ -237,6 +290,7 @@ decodeControlMessage(bufferStore & buff)
int ver;
+ failed = false;
ver = buff.getByte(0);
// Series 3c returns '3', as does mclink. PsiWin 1.1
// returns version 2. We return whatever version we're
@@ -263,11 +317,12 @@ decodeControlMessage(bufferStore & buff)
// 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
+ } else {
cout << "ALERT!!!! Unexpected Protocol Version!! (No Series 5/3?)!" << endl;
+ failed = true;
+ }
break;
case NCON_MSG_CHANNEL_DISCONNECT:
@@ -318,7 +373,7 @@ RegisterAck(int chan, const char *name)
cout << "ncp: RegisterAck: chan=" << chan << endl;
for (int cNum = 1; cNum < maxLinks(); cNum++) {
channel *ch = channelPtr[cNum];
- if (ch && ch->getNcpChannel() == chan) {
+ if (isValidChannel(cNum) && ch->getNcpChannel() == chan) {
ch->setNcpConnectName(name);
ch->ncpRegisterAck();
return;
@@ -420,9 +475,20 @@ stuffToSend()
bool ncp::
hasFailed()
{
- if (failed)
- return true;
- return l->hasFailed();
+ bool lfailed = l->hasFailed();
+ if (failed || lfailed) {
+ if (verbose & NCP_DEBUG_LOG)
+ cout << "ncp: hasFailed: " << failed << ", " << lfailed << endl;
+ }
+ failed |= lfailed;
+ if (failed) {
+ if (lChan) {
+ channelPtr[lChan->getNcpChannel()] = NULL;
+ delete lChan;
+ }
+ lChan = NULL;
+ }
+ return failed;
}
bool ncp::
@@ -431,6 +497,12 @@ gotLinkChannel()
return (lChan != NULL);
}
+int ncp::
+getSpeed()
+{
+ return l->getSpeed();
+}
+
char *ncp::
ctrlMsgName(unsigned char msgType)
{
diff --git a/ncpd/ncp.h b/ncpd/ncp.h
index 72c5ca8..5a6a1ba 100644
--- a/ncpd/ncp.h
+++ b/ncpd/ncp.h
@@ -27,14 +27,33 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
+#include <vector>
+
#include "bufferstore.h"
#include "linkchan.h"
+#include "ppsocket.h"
+
class Link;
class channel;
#define NCP_DEBUG_LOG 1
#define NCP_DEBUG_DUMP 2
+/**
+ * Representation of a server process on the PC
+ * A dummy which does not allow connects for now.
+ */
+class PcServer {
+public:
+ PcServer(ppsocket *, string _name) { name = _name; }
+ ~PcServer() {}
+ bool clientConnect(int, int) { return false; }
+ string getName() { return name; }
+private:
+ string name;
+};
+
class ncp {
public:
ncp(const char *fname, int baud, unsigned short _verbose = 0);
@@ -51,9 +70,14 @@ public:
bool hasFailed();
bool gotLinkChannel();
+ PcServer *findPcServer(const char *name);
+ void registerPcServer(ppsocket *skt, const char *name);
+ void unregisterPcServer(PcServer *server);
+
void setVerbose(unsigned short);
unsigned short getVerbose();
short int getProtocolVersion();
+ int getSpeed();
private:
friend class Link;
@@ -87,6 +111,7 @@ private:
short int protocolVersion;
linkChan *lChan;
int maxChannels;
+ vector<PcServer> pcServers;
};
#endif
diff --git a/ncpd/packet.cc b/ncpd/packet.cc
index 84f0f66..1d3183b 100644
--- a/ncpd/packet.cc
+++ b/ncpd/packet.cc
@@ -138,10 +138,17 @@ static void *pump_run(void *arg)
}
}
-//static pthread_mutex_t outMutex;
-//static pthread_mutex_t inMutex;
};
+static const int baud_table[] = {
+ 115200,
+ 57600,
+ 38400,
+ 19200,
+ // Lower rates don't make sense ?!
+};
+#define BAUD_TABLE_SIZE (sizeof(baud_table) / sizeof(int))
+
packet::
packet(const char *fname, int _baud, Link *_link, unsigned short _verbose)
{
@@ -151,6 +158,7 @@ packet(const char *fname, int _baud, Link *_link, unsigned short _verbose)
baud = _baud;
theLINK = _link;
isEPOC = false;
+ justStarted = true;
// Initialize CRC table
crc_table[0] = 0;
@@ -174,12 +182,15 @@ packet(const char *fname, int _baud, Link *_link, unsigned short _verbose)
crcIn = crcOut = 0;
thisThread = pthread_self();
- fd = init_serial(devname, baud, 0);
+ realBaud = baud;
+ if (baud < 0) {
+ baud_index = 1;
+ realBaud = baud_table[0];
+ }
+ fd = init_serial(devname, realBaud, 0);
if (fd == -1)
lastFatal = true;
else {
-// pthread_mutex_init(&inMutex, NULL);
-// pthread_mutex_init(&outMutex, NULL);
signal(SIGUSR1, usr1handler);
pthread_create(&datapump, NULL, pump_run, this);
}
@@ -201,30 +212,46 @@ packet::
void packet::
reset()
{
+ if (fd != -1)
+ pthread_cancel(datapump);
+ outRead = outWrite = 0;
+ internalReset();
+ if (fd != -1)
+ pthread_create(&datapump, NULL, pump_run, this);
+}
+
+void packet::
+internalReset()
+{
if (verbose & PKT_DEBUG_LOG)
cout << "resetting serial connection" << endl;
if (fd != -1) {
- pthread_cancel(datapump);
ser_exit(fd);
fd = -1;
}
- usleep(100000);
- inRead = inWrite = outRead = outWrite = 0;
+ usleep(1000000);
+ inRead = inWrite = 0;
esc = false;
lastFatal = false;
serialStatus = -1;
lastSYN = startPkt = -1;
crcIn = crcOut = 0;
- fd = init_serial(devname, baud, 0);
- if (fd != -1)
- lastFatal = false;
- else {
-// pthread_mutex_init(&inMutex, NULL);
-// pthread_mutex_init(&outMutex, NULL);
- pthread_create(&datapump, NULL, pump_run, this);
+ realBaud = baud;
+ justStarted = true;
+ if (baud < 0) {
+ realBaud = baud_table[baud_index++];
+ if (baud_index >= BAUD_TABLE_SIZE)
+ baud_index = 0;
}
+
+ fd = init_serial(devname, realBaud, 0);
if (verbose & PKT_DEBUG_LOG)
- cout << "serial connection reset, fd=" << fd << endl;
+ cout << "serial connection set to " << dec << realBaud
+ << " baud, fd=" << fd << endl;
+ if (fd != -1) {
+ lastFatal = false;
+ realWrite();
+ }
}
short int packet::
@@ -245,6 +272,12 @@ setEpoc(bool _epoc)
isEPOC = _epoc;
}
+int packet::
+getSpeed()
+{
+ return realBaud;
+}
+
void packet::
send(bufferStore &b)
{
@@ -350,6 +383,7 @@ findSync()
}
}
if (startPkt >= 0) {
+ justStarted = false;
while (p != inw) {
unsigned char c = inBuffer[p];
switch (inCRCstate) {
@@ -393,7 +427,6 @@ findSync()
if (verbose & PKT_DEBUG_LOG)
cout << "packet: BAD CRC" << endl;
} else {
- // inQueue += rcv;
if (verbose & PKT_DEBUG_LOG) {
cout << "packet: << ";
if (verbose & PKT_DEBUG_DUMP)
@@ -412,6 +445,18 @@ findSync()
inc1(p);
}
lastSYN = p;
+ } else {
+ // If we get here, no sync was found.
+ // If we are just started and the amount of received data exceeds
+ // 15 bytes, the baudrate is obviously wrong.
+ // (or the connected device is not an EPOC device). Reset the
+ // serial connection and try next baudrate, if auto-baud is set.
+ if (justStarted) {
+ int rx_amount = (inw > inRead) ?
+ inw - inRead : BUFLEN - inRead + inw;
+ if (rx_amount > 15)
+ internalReset();
+ }
}
}
@@ -422,8 +467,8 @@ linkFailed()
int res;
bool failed = false;
- if (lastFatal)
- reset();
+ if (fd == -1)
+ return false;
res = ioctl(fd, TIOCMGET, &arg);
if (res < 0)
lastFatal = true;
@@ -453,10 +498,8 @@ linkFailed()
|| ((arg & TIOCM_DSR) == 0)
#endif
) {
- // eat possible junk on line
- //while (read(fd, &res, sizeof(res)) > 0)
- // ;
failed = true;
+ justStarted = true;
}
if ((verbose & PKT_DEBUG_LOG) && lastFatal)
cout << "packet: linkFATAL\n";
diff --git a/ncpd/packet.h b/ncpd/packet.h
index aa0b90c..dcf01cc 100644
--- a/ncpd/packet.h
+++ b/ncpd/packet.h
@@ -57,6 +57,7 @@ public:
void setEpoc(bool);
void setVerbose(short int);
short int getVerbose();
+ int getSpeed();
bool linkFailed();
void reset();
@@ -71,6 +72,7 @@ private:
void opByte(unsigned char a);
void opCByte(unsigned char a, unsigned short *crc);
void realWrite();
+ void internalReset();
Link *theLINK;
pthread_t datapump;
@@ -98,10 +100,14 @@ private:
int foundSync;
int fd;
int serialStatus;
+ int baud_index;
+ int realBaud;
short int verbose;
bool esc;
bool lastFatal;
bool isEPOC;
+ bool justStarted;
+
char *devname;
int baud;
};
diff --git a/ncpd/socketchan.cc b/ncpd/socketchan.cc
index 83d0695..fe2b683 100644
--- a/ncpd/socketchan.cc
+++ b/ncpd/socketchan.cc
@@ -32,6 +32,7 @@
#include "socketchan.h"
#include "ncp.h"
#include <ppsocket.h>
+#include <rfsv.h>
socketChan:: socketChan(ppsocket * _skt, ncp * _ncpController):
channel(_ncpController)
@@ -72,11 +73,10 @@ ncpCommand(bufferStore & a)
{
// 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();
+ const char *str = a.getString(4);
bool ok = false;
- if (!strncmp(str+4, "INFO", 4)) {
+ if (!strncmp(str, "INFO", 4)) {
// Send information discovered during the receipt of the
// NCON_MSG_NCP_INFO message.
a.init();
@@ -94,26 +94,50 @@ ncpCommand(bufferStore & a)
}
skt->sendBufferStore(a);
ok = true;
- } else if (!strncmp(str+4, "CONN", 4)) {
+ } else if (!strncmp(str, "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)) {
+ } else if (!strncmp(str, "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)) {
+ } else if (!strncmp(str, "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;
+ } else if (!strncmp(str, "GSPD", 4)) {
+ // Get Speed of serial device
+ cerr << "socketChan:: GETSPEED" << endl;
+ a.init();
+ a.addByte(rfsv::E_PSI_GEN_NONE);
+ a.addDWord(ncpGetSpeed());
+ skt->sendBufferStore(a);
+ ok = true;
+ } else if (!strncmp(str, "REGS", 4)) {
+ // Register a server-process on the PC side.
+ a.init();
+ const char *name = a.getString(8);
+ if (ncpFindPcServer(name))
+ a.addByte(rfsv::E_PSI_FILE_EXIST);
+ else {
+ ncpRegisterPcServer(skt, name);
+ a.addByte(rfsv::E_PSI_GEN_NONE);
+ }
+ skt->sendBufferStore(a);
+ ok = true;
}
- if (!ok)
+ if (!ok) {
cerr << "socketChan:: received unknown NCP command (" << a << ")" << endl;
+ a.init();
+ a.addByte(rfsv::E_PSI_GEN_NSUP);
+ skt->sendBufferStore(a);
+ }
return ok;
}
@@ -223,6 +247,12 @@ socketPoll()
ncpDisconnect();
skt->closeSocket();
} else if (res == 1) {
+ if (a.getLen() > 8 && !strncmp(a.getString(), "NCP$", 4)) {
+ if (!ncpCommand(a))
+ cerr << "ncpd: command " << a << " unrecognized."
+ << endl;
+ return;
+ }
ncpSend(a);
}
} else if (time(0) > (tryStamp + 15))
diff --git a/plpbackup/plpbackup.cc b/plpbackup/plpbackup.cc
index 66dd780..cbd211c 100644
--- a/plpbackup/plpbackup.cc
+++ b/plpbackup/plpbackup.cc
@@ -26,6 +26,7 @@
#endif
#include <sys/types.h>
+#include <sys/wait.h>
#include <dirent.h>
#include <fstream>
#include <strstream>
@@ -42,6 +43,7 @@
#include <errno.h>
#include <pwd.h>
#include <getopt.h>
+#include <fcntl.h>
#include <plpintl.h>
#include <ppsocket.h>
@@ -68,6 +70,7 @@ unsigned long totalBytes = 0;
unsigned long fileSize = 0;
PlpDir toBackup;
+PlpDir toRestore;
vector<string> driveList;
vector<string> archList;
vector<string> savedCommands;
@@ -115,7 +118,7 @@ generateBackupName()
static const char * const
generateTmpDir()
{
- char *tmpdir;
+ const char *tmpdir;
static char nbuf[4096];
if (!(tmpdir = getenv("TMPDIR")))
@@ -217,7 +220,7 @@ startPrograms() {
if (verbose > 0)
cout << _("Restarting programs ...") << endl;
- for (int i = 0; i < savedCommands.size(); i++) {
+ for (unsigned int i = 0; i < savedCommands.size(); i++) {
int firstBlank = savedCommands[i].find(' ');
string cmd = string(savedCommands[i], 0, firstBlank);
string arg = string(savedCommands[i], firstBlank + 1);
@@ -240,7 +243,7 @@ startPrograms() {
// not registered in the Psion's path properly. Now try
// the ususal \System\Apps\<AppName>\<AppName>.app
// on all drives.
- if (cmd.find('\\') == -1) {
+ if (cmd.find('\\') == cmd.npos) {
u_int32_t devbits;
if ((res = Rfsv->devlist(devbits)) == rfsv::E_PSI_GEN_NONE) {
int i;
@@ -312,7 +315,7 @@ collectFiles(bool &found, const char *dir) {
if ((res = Rfsv->dir(tmp.c_str(), files)) != rfsv::E_PSI_GEN_NONE)
cerr << "Error: " << res << endl;
else
- for (int i = 0; i < files.size(); i++) {
+ for (unsigned int i = 0; i < files.size(); i++) {
PlpDirent e = files[i];
if (checkAbort())
@@ -337,7 +340,7 @@ collectFiles(bool &found, const char *dir) {
static int
reportProgress(void *, u_int32_t size)
{
- unsigned long percent;
+ unsigned long percent = 0;
char pstr[10];
char bstr[10];
@@ -347,13 +350,19 @@ reportProgress(void *, u_int32_t size)
return 1;
switch (verbose) {
case 1:
- percent = (totalBytes + size) * 100 / backupSize;
+ if (backupSize == 0)
+ percent = 100;
+ else
+ percent = (totalBytes + size) * 100 / backupSize;
break;
case 2:
- percent = size * 100 / fileSize;
+ if (fileSize == 0)
+ percent = 100;
+ else
+ percent = size * 100 / fileSize;
break;
}
- sprintf(pstr, " %3d%%", percent);
+ sprintf(pstr, " %3ld%%", percent);
memset(bstr, 8, sizeof(bstr));
bstr[strlen(pstr)] = '\0';
printf("%s%s", pstr, bstr);
@@ -443,7 +452,7 @@ startMessage(const char *arch)
cout << "all drives";
else {
cout << "Drive ";
- for (int i = 0; i < driveList.size(); i++) {
+ for (unsigned int i = 0; i < driveList.size(); i++) {
cout << driveList[i++];
if (i < (driveList.size() - 1))
cout << ", ";
@@ -480,18 +489,501 @@ runFormat()
return 0;
}
+static int
+editfile(char *name)
+{
+ int shin, shout, sherr;
+ int mode_out, mode_err;
+ int status;
+ int rc = -1;
+ int rerrno = 0;
+ int pid, w;
+
+#ifdef POSIX_SIGNALS
+ sigset_t sigset_mask, sigset_omask;
+ struct sigaction act, iact, qact;
+
+#else
+#ifdef BSD_SIGNALS
+ int mask;
+ struct sigvec vec, ivec, qvec;
+
+#else
+ RETSIGTYPE (*istat) (int), (*qstat) (int);
+#endif
+#endif
+
+ /* setup default file descriptor numbers */
+ shin = 0;
+ shout = 1;
+ sherr = 2;
+
+ /* set the file modes for stdout and stderr */
+ mode_out = mode_err = O_WRONLY | O_CREAT;
+
+ /* Make sure we don't flush this twice, once in the subprocess. */
+ fflush (stdout);
+ fflush (stderr);
+
+ /* The output files, if any, are now created. Do the fork and dups.
+
+ We use vfork not so much for a performance boost (the
+ performance boost, if any, is modest on most modern unices),
+ but for the sake of systems without a memory management unit,
+ which find it difficult or impossible to implement fork at all
+ (e.g. Amiga). The other solution is spawn (see
+ windows-NT/run.c). */
+
+#ifdef HAVE_VFORK
+ pid = vfork ();
+#else
+ pid = fork ();
+#endif
+ if (pid == 0)
+ {
+
+#ifdef SETXID_SUPPORT
+ /*
+ ** This prevents a user from creating a privileged shell
+ ** from the text editor when the SETXID_SUPPORT option is selected.
+ */
+ if (!strcmp (run_argv[0], Editor) && setegid (getgid ()))
+ {
+ error (0, errno, "cannot set egid to gid");
+ _exit (127);
+ }
+#endif
+
+ /* dup'ing is done. try to run it now */
+ char *editor = getenv("EDITOR");
+ if (!editor)
+ editor = "vi";
+ execlp (editor, editor, name, NULL);
+ perror(editor);
+ _exit (127);
+ }
+ else if (pid == -1)
+ {
+ rerrno = errno;
+ goto out;
+ }
+
+ /* the parent. Ignore some signals for now */
+#ifdef POSIX_SIGNALS
+ act.sa_handler = SIG_IGN;
+ (void) sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ (void) sigaction (SIGINT, &act, &iact);
+ (void) sigaction (SIGQUIT, &act, &qact);
+#else
+#ifdef BSD_SIGNALS
+ memset ((char *) &vec, 0, sizeof (vec));
+ vec.sv_handler = SIG_IGN;
+ (void) sigvec (SIGINT, &vec, &ivec);
+ (void) sigvec (SIGQUIT, &vec, &qvec);
+#else
+ istat = signal (SIGINT, SIG_IGN);
+ qstat = signal (SIGQUIT, SIG_IGN);
+#endif
+#endif
+
+ /* wait for our process to die and munge return status */
+#ifdef POSIX_SIGNALS
+ while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+ ;
+#else
+ while ((w = wait (&status)) != pid) {
+ if (w == -1 && errno != EINTR)
+ break;
+ }
+#endif
+
+ if (w == -1) {
+ rc = -1;
+ rerrno = errno;
+ }
+#ifndef VMS /* status is return status */
+ else if (WIFEXITED (status))
+ rc = WEXITSTATUS (status);
+ else if (WIFSIGNALED (status)) {
+ if (WTERMSIG (status) == SIGPIPE)
+ perror("broken pipe");
+ rc = 2;
+ } else
+ rc = 1;
+#else /* VMS */
+ rc = WEXITSTATUS (status);
+#endif /* VMS */
+
+ /* restore the signals */
+#ifdef POSIX_SIGNALS
+ (void) sigaction (SIGINT, &iact, (struct sigaction *) NULL);
+ (void) sigaction (SIGQUIT, &qact, (struct sigaction *) NULL);
+#else
+#ifdef BSD_SIGNALS
+ (void) sigvec (SIGINT, &ivec, (struct sigvec *) NULL);
+ (void) sigvec (SIGQUIT, &qvec, (struct sigvec *) NULL);
+#else
+ (void) signal (SIGINT, istat);
+ (void) signal (SIGQUIT, qstat);
+#endif
+#endif
+
+ out:
+ if (rerrno)
+ errno = rerrno;
+ return (rc);
+}
+
static void
-runRestore()
+collectIndex(FILE *f, const char *archname)
{
+ char buf[1024];
+ string drives;
int i;
+
+ PlpDir indexSel;
+ PlpDir indexRestore;
+ while (fgets(buf, sizeof(buf), f)) {
+ unsigned long attr;
+ unsigned long size;
+ unsigned long timeLo;
+ unsigned long timeHi;
+ char drive = buf[36];
+
+ char *p = strrchr(buf, '\n');
+ if (p)
+ *p = '\0';
+ if (drive != '!') {
+ sscanf(buf, "%08lx %08lx %08lx %08lx ",
+ &timeHi, &timeLo, &size, &attr);
+ PlpDirent e(size, attr, timeHi, timeLo, &buf[36]);
+ indexSel.push_back(e);
+ if (drives.find(drive) == drives.npos)
+ drives += drive;
+ }
+ }
+ // drives now contains the drive-chars of all drives found in
+ // the backup.
+ if (!drives.empty()) {
+ cout << "It contains Backups of drive ";
+ for (i = 0; i < drives.size(); i++) {
+ if (i>0) {
+ if (i < (drives.size() - 1))
+ cout << ", ";
+ else
+ if (drives.size() > 1)
+ cout << " and ";
+ }
+ cout << drives[i] << ":";
+ }
+ cout << endl;
+
+ // Check, if one of the drives is in driveList (commandline args)
+ bool select = false;
+ for (i = 0; i < driveList.size(); i++) {
+ if (drives.find(driveList[i][0]) != drives.npos)
+ select = true;
+ }
+ if (select) {
+ cout << "Do you want to select individual files from this archive? (y/N)" << endl;
+ const char *validA = _("Y");
+ char answer;
+ cin >> answer;
+ if (toupper(answer) == *validA) {
+ strcpy(buf, "/tmp/plpbackupL_XXXXXX");
+ int fd = mkstemp(buf);
+ if (fd == -1) {
+ perror("mkstemp");
+ exit(-1);
+ }
+ FILE *tf = fdopen(fd, "w");
+ fprintf(tf, "# Edit this file to you needs and save it\n");
+ fprintf(tf, "# Change the 'N' in the first column to 'Y'\n");
+ fprintf(tf, "# if you want a file to be restored.\n");
+ fprintf(tf, "# DO NOT INSERT ANY LINES!\n");
+ for (i = 0; i < indexSel.size(); i++)
+ for (int j = 0; j < driveList.size(); j++)
+ if (*(indexSel[i].getName()) == driveList[j][0])
+ fprintf(tf, "N %s\n", indexSel[i].getName());
+ fclose(tf);
+ if (editfile(buf) == -1) {
+ perror("Could not run external editor");
+ unlink(buf);
+ exit(-1);
+ }
+ tf = fopen(buf, "r");
+ if (!tf) {
+ perror(buf);
+ unlink(buf);
+ exit(-1);
+ }
+ unlink(buf);
+ while (fgets(buf, sizeof(buf), tf)) {
+ char *p = strrchr(buf, '\n');
+ if (p)
+ *p = '\0';
+ if (buf[0] == 'Y') {
+ for (i = 0; i < indexSel.size(); i++)
+ if (!strcmp(indexSel[i].getName(), &buf[2]))
+ indexRestore.push_back(indexSel[i]);
+ }
+ }
+ fclose(tf);
+ } else {
+ for (i = 0; i < indexSel.size(); i++)
+ for (int j = 0; j < driveList.size(); j++)
+ if (*(indexSel[i].getName()) == driveList[j][0])
+ indexRestore.push_back(indexSel[i]);
+ }
+ } else
+ cout << "Archive skipped, because it does not contain any files on selected drives" << endl;
+ }
+ if (!indexRestore.empty()) {
+ PlpDirent e(0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, archname);
+ for (i = 0; i < indexRestore.size(); i++)
+ toRestore.push_back(indexRestore[i]);
+ }
+}
+
+static bool
+askOverwrite(const char *name)
+{
+ return true;
+}
+
+static int
+cps(unsigned long size, struct timeval *start, struct timeval *end)
+{
+ double t = tdiff(start, end);
+ if (t == 0.0)
+ return 99999;
+ else
+ return (int)(((double)size) / t);
+}
+
+static void
+runRestore()
+{
+ unsigned int i;
+ char indexbuf[40];
ostrstream tarcmd;
+ string dstPath;
+ struct timeval start_tv, end_tv, cstart_tv, cend_tv, sstart_tv, send_tv;
+
for (i = 0; i < archList.size(); i++) {
tarcmd << "tar --to-stdout -xzf " << archList[i]
<< " 'KPsion*Index'" << '\0';
+ char backupType = '?';
FILE *f = popen(tarcmd.str(), "r");
-
+ if (!f) {
+ perror("Could not get backup index");
+ continue;
+ }
+ fgets(indexbuf, sizeof(indexbuf), f);
+ if (!strncmp(indexbuf, "#plpbackup index ", 17))
+ backupType = indexbuf[17];
+ switch (backupType) {
+ case 'F':
+ cout << "'" << archList[i] << "' is a full backup" << endl;
+ collectIndex(f, archList[i].c_str());
+ break;
+ case 'I':
+ cout << "'" << archList[i] << "' is a incremental backup" << endl;
+ collectIndex(f, archList[i].c_str());
+ break;
+ default:
+ cerr << "'" << archList[i] << "' is NOT a plpbackup" << endl;
+ break;
+ }
pclose(f);
}
+ if (!toBackup.empty()) {
+ dstPath = "";
+ backupSize = backupCount = 0;
+ // Calculate number of files and total bytecount
+ for (i = 0; i < toRestore.size(); i++) {
+ backupSize += toBackup[i].getSize();
+ backupCount++;
+ }
+ // Stop all programs on Psion
+ stopPrograms();
+ string dest;
+ string pDir;
+ for (i = 0; i < toBackup.size(); i++) {
+ PlpDirent e = toBackup[i];
+ Enum<rfsv::errs> res;
+ u_int32_t handle;
+ struct timeval fstart_tv, fend_tv;
+ const char *fn = e.getName();
+
+ if ((e.getSize() == 0xdeadbeef) && (e.getAttr() == 0xdeadbeef) &&
+ (e.getPsiTime().getPsiTimeLo() == 0xdeadbeef) &&
+ (e.getPsiTime().getPsiTimeHi() == 0xdeadbeef)) {
+ if (!dstPath.empty())
+ rmrf(dstPath.c_str());
+ dstPath = generateTmpDir();
+ tarcmd.flush();
+ tarcmd << "tar xCf " << dstPath << " " << fn << '\0';
+ system(tarcmd.str());
+ }
+ if (checkAbort()) {
+ // remove temporary dir
+ rmrf(dstPath.c_str());
+ // restart previously killed programs
+ startPrograms();
+ cout << _("Restore aborted by user") << endl;
+ return;
+ }
+ dest = dstPath;
+ dest += '/';
+ dest += psion2unix(fn);
+ fileSize = e.getSize();
+ if (verbose > 1)
+ cout << _("Restore ") << fn << flush;
+
+ string cpDir(fn);
+ int bslash = cpDir.rfind('\\');
+ if (bslash != cpDir.npos)
+ cpDir.resize(bslash);
+
+ if (pDir != cpDir) {
+ pDir = cpDir;
+ res = Rfsv->mkdir(pDir.c_str());
+ if ((res != rfsv::E_PSI_GEN_NONE) &&
+ (res != rfsv::E_PSI_FILE_EXIST)) {
+ cerr << "Could not create directory " << pDir << ": "
+ << res << endl;
+ continue;
+ }
+ }
+
+ res = Rfsv->fcreatefile(
+ Rfsv->opMode(rfsv::PSI_O_RDWR), fn, handle);
+ if (res == rfsv::E_PSI_FILE_EXIST) {
+ if (!askOverwrite(fn))
+ continue;
+ res = Rfsv->freplacefile(
+ Rfsv->opMode(rfsv::PSI_O_RDWR), fn, handle);
+ }
+ if (res != rfsv::E_PSI_GEN_NONE) {
+ cerr << "Could not create " << fn << ": " << res << endl;
+ continue;
+ }
+ Rfsv->fclose(handle);
+ gettimeofday(&fstart_tv, NULL);
+ res = Rfsv->copyToPsion(dest.c_str(), fn, NULL, cab);
+ if (res == rfsv::E_PSI_GEN_NONE) {
+ u_int32_t oldattr;
+ res = Rfsv->fgetattr(fn, oldattr);
+ if (res != rfsv::E_PSI_GEN_NONE) {
+ cerr << "Could not get attributes of " << fn << ": " << res << endl;
+ continue;
+ }
+ u_int32_t mask = e.getAttr() ^ oldattr;
+ u_int32_t sattr = e.getAttr() & mask;
+ u_int32_t dattr = ~sattr & mask;
+ int retry = 10;
+ // Retry, because file somtimes takes some time
+ // to close;
+ do {
+ res = Rfsv->fsetattr(fn, sattr, dattr);
+ if (res != rfsv::E_PSI_GEN_NONE)
+ usleep(100000);
+ retry--;
+ } while ((res != rfsv::E_PSI_GEN_NONE) && (retry > 0));
+ if (res != rfsv::E_PSI_GEN_NONE) {
+ cerr << "Could not set attributes of" << fn << ": "
+ << res << endl;
+ continue;
+ }
+ retry = 10;
+ do {
+ res = Rfsv->fsetmtime(fn, e.getPsiTime());
+ if (res != rfsv::E_PSI_GEN_NONE)
+ usleep(100000);
+ retry--;
+ } while ((res != rfsv::E_PSI_GEN_NONE) && (retry > 0));
+ if (res != rfsv::E_PSI_GEN_NONE) {
+ cerr << "Could not set modification time of " << fn << ": "
+ << res << endl;
+ continue;
+ }
+ }
+ if (checkAbort()) {
+ // remove temporary dir
+ rmrf(dstPath.c_str());
+ // restart previously killed programs
+ startPrograms();
+ cout << _("Backup aborted by user") << endl;
+ return;
+ }
+ gettimeofday(&fend_tv, NULL);
+ if (verbose > 1)
+ cout << " " << cps(fileSize, &fstart_tv, &fend_tv)
+ << " CPS " << endl;
+ totalBytes += fileSize;
+ if (res != rfsv::E_PSI_GEN_NONE) {
+ if (skipError) {
+ e.setName("!");
+ if (verbose > 0)
+ cerr << _("Skipping ") << fn << ": "
+ << res << endl;
+ } else {
+ cerr << _("Error during restore of ") << fn << ": "
+ << res << endl;
+ if (isatty(0)) {
+ bool askLoop = true;
+ do {
+ char answer;
+ string vans = _("STAR");
+
+ cerr << _("(S)kip all, Skip (t)his, (A)bort, (R)etry: ")
+ << flush;
+ cin >> answer;
+ switch (vans.find(toupper(answer))) {
+ case 0:
+ skipError = true;
+ // fall thru
+ case 1:
+ e.setName("!");
+ askLoop = false;
+ break;
+ case 2:
+ i = toBackup.size();
+ askLoop = false;
+ break;
+ case 3:
+ if (verbose > 1)
+ cout << _("Restore ") << fn << flush;
+ break;
+ res = Rfsv->copyFromPsion(fn, dest.c_str(), NULL, cab);
+ if (checkAbort()) {
+ // remove temporary dir
+ rmrf(dstPath.c_str());
+ // restart previously killed programs
+ startPrograms();
+ cout << _("Restore aborted by user")
+ << endl;
+ return;
+ }
+ if (verbose > 1)
+ cout << endl;
+ if (res != rfsv::E_PSI_GEN_NONE) {
+ cerr << _("Error during restore of ")
+ << fn << ": " << res << endl;
+ } else
+ askLoop = false;
+ break;
+ }
+ } while (askLoop);
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
}
static void
@@ -539,7 +1031,7 @@ runBackup()
if ((devbits & 1) && Rfsv->devinfo(i + 'A', psidr)
== rfsv::E_PSI_GEN_NONE) {
if (psidr.getMediaType() != 7) {
- sprintf(drive, "%c:\0", 'A' + i);
+ sprintf(drive, "%c:", 'A' + i);
if (verbose > 0)
cout << _("Scanning Drive ") << drive << " ..."
<< flush;
@@ -622,8 +1114,7 @@ runBackup()
gettimeofday(&fend_tv, NULL);
if (verbose > 1)
cout << " "
- << (int)((double)fileSize / tdiff(&fstart_tv, &fend_tv))
- << " CPS" << endl;
+ << cps(fileSize, &fstart_tv, &fend_tv) << " CPS" << endl;
totalBytes += fileSize;
if (res != rfsv::E_PSI_GEN_NONE) {
if (skipError) {
@@ -785,7 +1276,7 @@ runBackup()
cout << _("Time for transfer: ") << tdiff(&cstart_tv, &cend_tv)
<< endl;
cout << _("Average transfer speed: ")
- << (double)backupSize / tdiff(&cstart_tv, &cend_tv) << endl;
+ << cps(backupSize, &cstart_tv, &cend_tv) << endl;
}
}
}
diff --git a/plpftp/ftp.cc b/plpftp/ftp.cc
index 2ce30af..c94afc4 100644
--- a/plpftp/ftp.cc
+++ b/plpftp/ftp.cc
@@ -224,7 +224,9 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv)
if ((res = r.getOwnerInfo(b)) == rfsv::E_PSI_GEN_NONE) {
r.getMachineType(machType);
if (!once) {
- cout << _("Connected to a ") << machType << _(", OwnerInfo:") << endl;
+ int speed = a.getSpeed();
+ cout << _("Connected to a ") << machType << _(" at ")
+ << speed << _(" baud, OwnerInfo:") << endl;
while (!b.empty())
cout << " " << b.pop().getString() << endl;
cout << endl;
@@ -765,9 +767,15 @@ session(rfsv & a, rpcs & r, int xargc, char **xargv)
continue;
}
// RPCS commands
+#define EXPERIMENTAL
#ifdef EXPERIMENTAL
if (!strcmp(argv[0], "x")) {
- r.regOpenIter();
+ u_int16_t hhh;
+ if (r.regOpenIter(-1, "%PDF-", hhh) == rfsv::E_PSI_GEN_NONE) {
+ Enum<rfsv::errs> res;
+ while ((res = r.regReadIter(hhh)) == rfsv::E_PSI_GEN_NONE)
+ ;;
+ }
continue;
}
if (!strcmp(argv[0], "y")) {