plptools
Loading...
Searching...
No Matches
rfsv.cc
Go to the documentation of this file.
1/*
2 * This file is part of plptools.
3 *
4 * Copyright (C) 1999 Philip Proudman <philip.proudman@btinternet.com>
5 * Copyright (C) 1999 Matt J. Gumbley <matt@gumbley.demon.co.uk>
6 * Copyright (C) 1999-2001 Fritz Elfert <felfert@to.com>
7 * Copyright (c) 2026 Jason Morley <hello@jbmorley.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * along with this program; if not, see <https://www.gnu.org/licenses/>.
21 *
22 */
23#include "config.h"
24
25#include "rfsv.h"
26
27#include "bufferstore.h"
28#include "drive.h"
29#include "Enum.h"
30#include "ncpclient.h"
31#include "plpdirent.h"
32#include "rfsv16.h"
33#include "rfsv32.h"
34#include "tcpsocket.h"
35
36using namespace std;
37
39 stringRep.add(RFSV::E_PSI_GEN_NONE, N_("no error"));
40 stringRep.add(RFSV::E_PSI_GEN_FAIL, N_("general"));
41 stringRep.add(RFSV::E_PSI_GEN_ARG, N_("bad argument"));
42 stringRep.add(RFSV::E_PSI_GEN_OS, N_("OS error"));
43 stringRep.add(RFSV::E_PSI_GEN_NSUP, N_("not supported"));
44 stringRep.add(RFSV::E_PSI_GEN_UNDER, N_("numeric underflow"));
45 stringRep.add(RFSV::E_PSI_GEN_OVER, N_("numeric overflow"));
46 stringRep.add(RFSV::E_PSI_GEN_RANGE, N_("numeric exception"));
47 stringRep.add(RFSV::E_PSI_GEN_INUSE, N_("in use"));
48 stringRep.add(RFSV::E_PSI_GEN_NOMEMORY, N_("out of memory"));
49 stringRep.add(RFSV::E_PSI_GEN_NOSEGMENTS, N_("out of segments"));
50 stringRep.add(RFSV::E_PSI_GEN_NOSEM, N_("out of semaphores"));
51 stringRep.add(RFSV::E_PSI_GEN_NOPROC, N_("out of processes"));
52 stringRep.add(RFSV::E_PSI_GEN_OPEN, N_("already open"));
53 stringRep.add(RFSV::E_PSI_GEN_NOTOPEN, N_("not open"));
54 stringRep.add(RFSV::E_PSI_GEN_IMAGE, N_("bad image"));
55 stringRep.add(RFSV::E_PSI_GEN_RECEIVER, N_("receiver error"));
56 stringRep.add(RFSV::E_PSI_GEN_DEVICE, N_("device error"));
57 stringRep.add(RFSV::E_PSI_GEN_FSYS, N_("no filesystem"));
58 stringRep.add(RFSV::E_PSI_GEN_START, N_("not ready"));
59 stringRep.add(RFSV::E_PSI_GEN_NOFONT, N_("no font"));
60 stringRep.add(RFSV::E_PSI_GEN_TOOWIDE, N_("too wide"));
61 stringRep.add(RFSV::E_PSI_GEN_TOOMANY, N_("too many"));
62 stringRep.add(RFSV::E_PSI_FILE_EXIST, N_("file already exists"));
63 stringRep.add(RFSV::E_PSI_FILE_NXIST, N_("no such file"));
64 stringRep.add(RFSV::E_PSI_FILE_WRITE, N_("write error"));
65 stringRep.add(RFSV::E_PSI_FILE_READ, N_("read error"));
66 stringRep.add(RFSV::E_PSI_FILE_EOF, N_("end of file"));
67 stringRep.add(RFSV::E_PSI_FILE_FULL, N_("disk/serial read buffer full"));
68 stringRep.add(RFSV::E_PSI_FILE_NAME, N_("invalid name"));
69 stringRep.add(RFSV::E_PSI_FILE_ACCESS, N_("access denied"));
70 stringRep.add(RFSV::E_PSI_FILE_LOCKED, N_("resource locked"));
71 stringRep.add(RFSV::E_PSI_FILE_DEVICE, N_("no such device"));
72 stringRep.add(RFSV::E_PSI_FILE_DIR, N_("no such directory"));
73 stringRep.add(RFSV::E_PSI_FILE_RECORD, N_("no such record"));
74 stringRep.add(RFSV::E_PSI_FILE_RDONLY, N_("file is read-only"));
75 stringRep.add(RFSV::E_PSI_FILE_INV, N_("invalid I/O operation"));
76 stringRep.add(RFSV::E_PSI_FILE_PENDING, N_("I/O pending (not yet completed)"));
77 stringRep.add(RFSV::E_PSI_FILE_VOLUME, N_("invalid volume name"));
78 stringRep.add(RFSV::E_PSI_FILE_CANCEL, N_("cancelled"));
79 stringRep.add(RFSV::E_PSI_FILE_ALLOC, N_("no memory for control block"));
80 stringRep.add(RFSV::E_PSI_FILE_DISC, N_("unit disconnected"));
81 stringRep.add(RFSV::E_PSI_FILE_CONNECT, N_("already connected"));
82 stringRep.add(RFSV::E_PSI_FILE_RETRAN, N_("retransmission threshold exceeded"));
83 stringRep.add(RFSV::E_PSI_FILE_LINE, N_("physical link failure"));
84 stringRep.add(RFSV::E_PSI_FILE_INACT, N_("inactivity timer expired"));
85 stringRep.add(RFSV::E_PSI_FILE_PARITY, N_("serial parity error"));
86 stringRep.add(RFSV::E_PSI_FILE_FRAME, N_("serial framing error"));
87 stringRep.add(RFSV::E_PSI_FILE_OVERRUN, N_("serial overrun error"));
88 stringRep.add(RFSV::E_PSI_MDM_CONFAIL, N_("modem cannot connect to remote modem"));
89 stringRep.add(RFSV::E_PSI_MDM_BUSY, N_("remote modem busy"));
90 stringRep.add(RFSV::E_PSI_MDM_NOANS, N_("remote modem did not answer"));
91 stringRep.add(RFSV::E_PSI_MDM_BLACKLIST, N_("number blacklisted by the modem"));
92 stringRep.add(RFSV::E_PSI_FILE_NOTREADY, N_("drive not ready"));
93 stringRep.add(RFSV::E_PSI_FILE_UNKNOWN, N_("unknown media"));
94 stringRep.add(RFSV::E_PSI_FILE_DIRFULL, N_("directory full"));
95 stringRep.add(RFSV::E_PSI_FILE_PROTECT, N_("write-protected"));
96 stringRep.add(RFSV::E_PSI_FILE_CORRUPT, N_("media corrupt"));
97 stringRep.add(RFSV::E_PSI_FILE_ABORT, N_("aborted operation"));
98 stringRep.add(RFSV::E_PSI_FILE_ERASE, N_("failed to erase flash media"));
99 stringRep.add(RFSV::E_PSI_FILE_INVALID, N_("invalid file for DBF system"));
100 stringRep.add(RFSV::E_PSI_GEN_POWER, N_("power failure"));
101 stringRep.add(RFSV::E_PSI_FILE_TOOBIG, N_("too big"));
102 stringRep.add(RFSV::E_PSI_GEN_DESCR, N_("bad descriptor"));
103 stringRep.add(RFSV::E_PSI_GEN_LIB, N_("bad entry point"));
104 stringRep.add(RFSV::E_PSI_FILE_NDISC, N_("could not diconnect"));
105 stringRep.add(RFSV::E_PSI_FILE_DRIVER, N_("bad driver"));
106 stringRep.add(RFSV::E_PSI_FILE_COMPLETION, N_("operation not completed"));
107 stringRep.add(RFSV::E_PSI_GEN_BUSY, N_("server busy"));
108 stringRep.add(RFSV::E_PSI_GEN_TERMINATED, N_("terminated"));
109 stringRep.add(RFSV::E_PSI_GEN_DIED, N_("died"));
110 stringRep.add(RFSV::E_PSI_FILE_HANDLE, N_("bad handle"));
111 stringRep.add(RFSV::E_PSI_NOT_SIBO, N_("invalid operation for RFSV16"));
112 stringRep.add(RFSV::E_PSI_INTERNAL, N_("libplp internal error"));
114
115RFSV *RFSV::connect(const std::string &host, int port, Enum<ConnectionError> *error) {
116 return ncp_client::connect<RFSV, RFSV16, RFSV32>(host, port, false, error);
117}
118
119const char *RFSV::getConnectName(void) {
120 return "SYS$RFSV";
121}
122
124 socket_->closeSocket();
125}
126
127void RFSV::reconnect(void) {
128 socket_->reconnect();
129 operationId_ = 0;
130 reset();
131}
132
133void RFSV::reset(void) {
136 a.addStringT(getConnectName());
137 if (socket_->sendBufferStore(a)) {
138 if (socket_->getBufferStore(a) == 1) {
139 if (!strcmp(a.getString(0), "Ok"))
141 }
142 }
143}
144
146 return status_;
147}
148
149string RFSV::convertSlash(const string &name) {
150 string tmp = "";
151 for (const char *p = name.c_str(); *p; p++)
152 tmp += (*p == '/') ? '\\' : *p;
153 return tmp;
154}
155
156string RFSV::attr2String(const uint32_t attr) {
157 string tmp = "";
158 tmp += ((attr & PSI_A_DIR) ? 'd' : '-');
159 tmp += ((attr & PSI_A_READ) ? 'r' : '-');
160 tmp += ((attr & PSI_A_RDONLY) ? '-' : 'w');
161 tmp += ((attr & PSI_A_HIDDEN) ? 'h' : '-');
162 tmp += ((attr & PSI_A_SYSTEM) ? 's' : '-');
163 tmp += ((attr & PSI_A_ARCHIVE) ? 'a' : '-');
164 tmp += ((attr & PSI_A_VOLUME) ? 'v' : '-');
165
166 // EPOC
167 tmp += ((attr & PSI_A_NORMAL) ? 'n' : '-');
168 tmp += ((attr & PSI_A_TEMP) ? 't' : '-');
169 tmp += ((attr & PSI_A_COMPRESSED) ? 'c' : '-');
170 // SIBO
171 tmp[7] = ((attr & PSI_A_EXEC) ? 'x' : tmp[7]);
172 tmp[8] = ((attr & PSI_A_STREAM) ? 'b' : tmp[8]);
173 tmp[9] = ((attr & PSI_A_TEXT) ? 't' : tmp[9]);
174 return tmp;
175}
176
179 a.addStringT("NCP$GSPD");
180 if (!socket_->sendBufferStore(a))
181 return -1;
182 if (socket_->getBufferStore(a) != 1)
183 return -1;
184 if (a.getLen() != 5)
185 return -1;
186 if (a.getByte(0) != E_PSI_GEN_NONE)
187 return -1;
188 return a.getDWord(1);
189}
190
191Enum<RFSV::errs> RFSV::dir(const std::string &path,
192 bool recursive,
193 std::vector<PlpDirent> &_files) {
194 Enum<RFSV::errs> result;
195
196 // List the top level directory.
197 PlpDir entries;
198 result = dir(path.c_str(), entries);
199 if (result != RFSV::E_PSI_GEN_NONE) {
200 return result;
201 }
202
203 // List the inner directories.
204 std::vector<PlpDirent> files;
205 for (PlpDirent entry: entries) {
206 files.push_back(entry);
207 if (recursive && entry.isDirectory()) {
208 std::vector<PlpDirent> directoryFiles;
209 result = dir(entry.getPath(), recursive, directoryFiles);
210 if (result != RFSV::E_PSI_GEN_NONE) {
211 return result;
212 }
213 files.insert(files.end(), directoryFiles.begin(), directoryFiles.end());
214 }
215 }
216 _files = files;
218}
219
220Enum<RFSV::errs> RFSV::drives(std::vector<Drive> &_drives) {
221 Enum<RFSV::errs> result;
222
223 // Get the supported drives.
224 uint32_t driveBits = 0;
225 result = devlist(driveBits);
226 if (result != RFSV::E_PSI_GEN_NONE) {
227 return result;
228 }
229
230 // Convert them to drive letters.
231 std::vector<char> driveLetters;
232 for (int i = 0; i < 26; i++) {
233 if (driveBits & (1 << i)) {
234 driveLetters.push_back('A' + i);
235 }
236 }
237
238 // Iterate over the drive letters and get the info for the available drives.
239 std::vector<Drive> drives;
240 for (const auto &driveLetter : driveLetters) {
241 Drive drive;
242 result = devinfo(driveLetter, drive);
243 if (result == RFSV::E_PSI_FILE_NOTREADY) {
244 // Ignore drives that aren't available.
245 continue;
246 }
247 if (result != RFSV::E_PSI_GEN_NONE) {
248 return result;
249 }
250 drives.push_back(drive);
251 }
252
253 _drives = drives;
255}
#define ENUM_DEFINITION_END(EnumName)
Definition: Enum.h:297
#define ENUM_DEFINITION_BEGIN(EnumName, initWith)
Helper macro to construct an enumeration wrapper Enum<E> for a specific enum type.
Definition: Enum.h:292
A generic container for an array of bytes.
Definition: bufferstore.h:36
A class representing information about a Disk drive on the psion.
Definition: drive.h:51
Wrapper class featuring range-checking and string representation of enumerated values.
Definition: Enum.h:135
A class, representing a directory entry of the Psion.
Definition: plpdirent.h:79
This is the implementation of the RFSV protocol for Psion series 3 (SIBO) variant.
Definition: rfsv16.h:35
Access remote file services of a Psion.
Definition: rfsv.h:79
const char * getConnectName()
Retrieves the PLP protocol name.
Definition: rfsv.cc:119
Enum< errs > drives(std::vector< Drive > &drives)
Definition: rfsv.cc:220
std::string attr2String(const uint32_t attr)
Converts a file attribute RFSV::file_attribs to human readable format, usable for showing them in dir...
Definition: rfsv.cc:156
Enum< errs > status_
Definition: rfsv.h:661
virtual ~RFSV()
Definition: rfsv.cc:123
Enum< errs > getStatus()
Retrieves the current connection status.
Definition: rfsv.cc:145
void reset()
Definition: rfsv.cc:133
void reconnect()
Definition: rfsv.cc:127
virtual Enum< errs > dir(const char *const name, PlpDir &ret)=0
Reads a directory on the Psion.
std::unique_ptr< TCPSocket > socket_
Definition: rfsv.h:660
int32_t operationId_
Definition: rfsv.h:662
virtual Enum< errs > devlist(uint32_t &devbits)=0
Retrieves available drives on the Psion.
virtual Enum< errs > devinfo(const char drive, Drive &dinfo)=0
Retrieves details about a drive.
static std::string convertSlash(const std::string &name)
Utility method, converts '/' to '\'.
Definition: rfsv.cc:149
int getSpeed()
Retrieve speed of serial link.
Definition: rfsv.cc:177
errs
The known error codes.
Definition: rfsv.h:113
@ E_PSI_FILE_DISC
Definition: rfsv.h:156
@ E_PSI_FILE_NOTREADY
Definition: rfsv.h:168
@ E_PSI_GEN_NONE
Definition: rfsv.h:114
@ PSI_A_NORMAL
Attributes, valid on EPOC only.
Definition: rfsv.h:207
@ PSI_A_TEXT
Definition: rfsv.h:215
@ PSI_A_ARCHIVE
Definition: rfsv.h:203
@ PSI_A_DIR
Definition: rfsv.h:202
@ PSI_A_EXEC
Definition: rfsv.h:213
@ PSI_A_HIDDEN
Definition: rfsv.h:200
@ PSI_A_COMPRESSED
Definition: rfsv.h:209
@ PSI_A_READ
Attributes, valid on SIBO only.
Definition: rfsv.h:212
@ PSI_A_STREAM
Definition: rfsv.h:214
@ PSI_A_VOLUME
Definition: rfsv.h:204
@ PSI_A_RDONLY
Attributes, valid on both EPOC and SIBO.
Definition: rfsv.h:199
@ PSI_A_TEMP
Definition: rfsv.h:208
@ PSI_A_SYSTEM
Definition: rfsv.h:201
ConnectionError
Errors that can occur when connecting to a PLP server.
Definition: doctest.h:522
static RFSV * a
Definition: main.cc:55
#define N_(String)
Definition: plpintl.h:35
stringRep add(RFSV::E_PSI_GEN_NONE, N_("no error"))
std::deque< class PlpDirent > PlpDir
Definition: rfsv.h:34
static void error(int line)
Definition: sismain.cpp:44
Description of a Psion-Device.
Definition: plpfuse.h:33