One of the things that was really useful early on, especially when I wasn't using IRC was to be able to just chat to someone one-to-one. There weren't many tools for it, and Alex Howarth asked me if I could write something. !Chat was the result - my first ZapRedraw application - and was apparently only about 2 hours of main development work. The rest was all bug fixing .
The application listened on a port above 2000 and when it got a connection
it would display a window and let you type messages to the other person,
unbuffered. It wasn't particularly clever really, and later I
incorporated much of the functionality into !JFTerm with the
ttylink listening port (except it was line buffered).
It wasn't all that much, but I was quite pleased that it came out so well.
David Thomas played with it and fixed a bunch of mistakes,
which made it a little better. Based around the way that '
worked at University, it allowed you to type in the top of the screen, and
the lower half was the other person's chat. Trying it now, it doesn't cope
so well with having the font hard-coded and not found. A few small fixes
down and it works again.
After implementing quite a few clients and servers, I got fed up with rewriting the same thing over and over again. The sequence for resolving a host and connecting to it, and for buffering line based input were common to most applications. I wrote EasySocket to make such things easier. It really isn't all that complicated.
The module had a very simple interface, which was equally easy to use from BASIC or Assembler. It had a few niceties that got added along the way, like monitoring of sockets (through Wimp pollwords) and towards the end, the ability to read the local port number and reading the remote address, for operations that had previously not needed it.
EasySocket was use in lots of my little programs, because... um...
it was really easy. It was supplied with a few examples that had
been knocked up to show how to use it - along with the API documentation
in the !ReadMe file. It included
EIRC, which may be the simplest IRC
client you can write - well, maybe not ... apparently it supports CTCP,
which makes it not quite the simplest .
The EDict server was a pretty simple (ok, incredibly simple) Dictionary server, using EasySocket as the simple line based communications system. It mostly conformed to RFC 2229, but had restrictions on line length. It was also restricted in that its database of words was quite limited. I only implemented a single database source (although it could handle many different sources), which knew about 4 words.
It was pretty fun though - I emailed the author of the RFC about some things that I'd found difficult in implementing the server. I got back a reply that essentially said 'there's a reference implementation, we don't expect people to write their own'. That took most of the fun away.
!LPRd was a lot more successful. Well, in the sense that it was actually used by some people and had a useful purpose. Initially it was intended as a demo of EasySocket, but I wanted to do something a bit more whizzy than just stream stuff to a printer. I implemented RFC 1179 quite faithfully, with all the operations supported. We understood the control file information for the host, user and the name and class of job - many of the other options were ignored and the types of data we supported were only the raw and formatted data (all the others were just rejected). Banners could be forced or created only when the control file requested it. The banners themselves were constructed by building a DrawFile using the class of print job as the template file. A few text fields in the DrawFile were substituted with the names from the control file, and the page printed. As far as I can tell, I even remembered to correctly call SWI PDriver_DeclareFonts so that it would work on a PostScript printer. Not sure if I ever actually tested that though.
All requests were queued to a buffer and printed in order - there was no queue jumping. Although the daemon 'supported' removing jobs, it would just acknowledge the remove without actually doing so. I imagine that was partly due to it being harder to do, and partly because it gives you the ability to kill off all the jobs before yours in order to jump the queue .
As with most of the daemons, it logged to SysLog so you always knew what it was doing.
With EasySocket it was very easy to write network applications. Most of the tools that I had written with it were just clients which connected to a server, did their work and disconnected. !TalkerD was really a test application to make sure that it was both working as expected, and that it was pretty simple to write a reasonably useful application with it.
Unlike !Chat, which I'd written using the Socket library directly and only provided a way for a single person to talk, !TalkerD used EasySocket for its network handling, and provided a place where many people could connect and talk. Instead of providing a display of its own, it made even the local users connect in over the TCP connection. Removing all the rendering and local communication made it a world simpler and meant that I could focus on getting the main application right.
That said, !TalkerD was heavily restricted by having static arrays for its user list. This meant that you had to configure the maximum number of users that could connect at a given time, which is really quite tacky. However, as the code was meant to show how you create a server, rather than how you manage dynamic lists, I'm not sure that it matters. I certainly don't think it was much of a worry.
Although it had a fixed number of users, it could support up to 5390 registered users (70*77, on old discs) at any time. Its handling of privileges for users was limited, although that was partly because the privileges you could have were limited. You could kick people and create new users and that was pretty much it.
David Ramsden created a heavily modified version, which he named !RISCtalk. It was great to see someone actually taking the code and running with it in such a useful way. It was quite a bit more advanced than my basic version, and they had fixed the bugs that they'd found too .
As a test and demonstration of EasySocket I think it worked out really quite well. On the other hand, as a useful tool for people to use, I don't think it had quite the audience. You had to have a particular group of people to want to run your own Talker server, and they usually had access to more appropriate systems (a Unix system, generally).
Back when Chris Johns and I were at University, Chris had Internet access in his room - a novel experience . One fun thing about it was that the access was all via a proxy - there was no NAT present. HTTP access was through a web proxy but anything else needed to go through a special proxy connection where you connected to a TCP port and supplied the host and port you wanted to go to. It would then forward all your traffic across the connection.
This wasn't particularly friendly, and made quite a few things more difficult. I don't remember if there was a SOCKS 5 proxy as well - I remember adding SOCKS 5 support to !JFTerm around that time, so it's possible that there was one. It meant that any connections to the outside had to have a special connection in order to work properly. Not ideal and it became a little more frustrating for us.
These days the student network would probably be set up with a NAT, so you wouldn't really have much of a problem with a lot of these things - even using the UPnP protocol to open external ports. But back in 1997 the student network had neither.
So, Chris and I created a virtual network stack.
The network stack on RISC OS was just a BSD 4.4 stack using the regular socket calls. The network stack on the Computer Science lab machines was a part of SunOS and was nearly identical - certainly most of the operations that you would perform in a regular Internet application were identical. The idea was that all the operations we perform on RISC OS could be transmitted to a remote lab machine and executed there. The results would then be returned back to the RISC OS system as the return codes and structures.
Not a particularly difficult thing.
Chris wrote the SunOS end, which listened on a port for connections and then read data blocks from it. Each block was then operated on by invoking the network operation that was requested. The response would then be sent back down the connection to the other end. Every interface had to have a custom veneer because the interfaces were different - some passed lots of data in structures, and some returned data in structures.
I implemented the other end - the RISC OS module - which sat over the Internet module and converted all the SWI calls into messages to send over the network to the far end. Each SWI had different parameters, so we had custom veneers at this end to serialise the data. Obviously there was a lot of to-and-fro about the interfaces. My module would start up, connect through the gateway to Chris' bit and then we'd pass messages back and forth as network operations happened.
In some cases the operations were slightly different - like we could use
FIOSLEEPTW setting on RISC OS, which had no meaning
for SunOS. We needed to emulate this in order for TaskWindow tasks to not
lock up the system.
The blocking sockets were eventually changed to all be non-blocking and polled manually, as that made it easier to handle the sleeping TaskWindow functions. It was quite amusing to know that you were running on an Internet stack on another machine - one which had a direct connection to the Internet - but it doesn't give you much other benefit. There was also the downside that you couldn't bind to the lower port numbers which were only usable for root.
We tried it with a few things - web browsers and IRC clients, particularly. It worked quite well, but nobody we connected to noticed any difference. It just looked like a proxied connection. Technically, I think the remote interface was quite neat, but it wasn't that useful.
Back in those days it was common to have a dial up connection and a modem that would make those funny little noises during negotiation. At one time I could tell apart at least a couple of the protocol negotiations from their sounds. These days I couldn't, but that was how very sad things were . Once the connection was running, however, most diallers turned off the modem sound because it was just noise. The little lights on the modem would blink to say that it was receiving or transmitting, and maybe one that said it was connected.
That required you to be able to see the modem. To be honest, I didn't really need to see the big block of plastic. They didn't get hot - because they're just a modem and whilst they did do compression and protocol negotiation and other stuff, they weren't that much in need of cooling. So, shove it behind a cupboard and it won't bother you. You don't even need to hear the connection noises.
But sometimes it was useful to see the lights. On a typical Internet call, the lights would be flickering on and off in time with the data. File downloads would keep the receive light on, whilst the transmit light would flicker with acknowledgements. Chatting on IRC would just flick the lights now and then as packets were transferred. Even web browsing was sane, and a 140 character message didn't take over half a megabyte to transfer (recent measurements taken on the size of a twitter web page showing a single tweet). Back in those good old days, you didn't have broadcasts and there wasn't a lot else going on in the background. So (generally) if your network connection was doing something and you didn't initiate it, you probably wanted to know.
So I wrote a little application called !SerLights. It was absolutely dumb,
but it made some pretty lights on the Iconbar which lit up when data was
being transmitted or being received. A little '
TX' light indicated that there was traffic in each direction.
At least a couple of people used it, which was nice.
The application itself was based on a slightly earlier work, from when Chris and I were at University. Instead of monitoring the serial port, the original application would track the state of the EconetA module. A module of my own would watch for Econet events, and if data was received or transmitted would keep track and notify the application. It's all so very simple!
Dynamic DNS updates
Back in the days of dial up Internet, directly connecting through RISC
OS (ah, the fun we had), it was useful to have a known, named host so
that you could give it to people for testing servers and the like. In
general, the names that were given to hosts on dial up were
unfriendly, although reasonable schemes like
dialup-5-75.shrew.billyisp.co.uk'. Sometimes they were
better, sometimes they were worse.
Demon had offered a service to always assign fixed addresses with
sensible reverse DNS, so some of us got used to that. The days of
knowing that '
willothewisp.demon.co.uk' was Matthew Godbolt
had begun to fade as dynamic IP assignment became the norm. Even still,
having a name that resolved to your dynamic IP was useful. A few
providers have offered dynamic DNS resolution over the years, but
initially I found 'Monolith' (
ml.org - now defunct) did a
nice job for us.
!MLDynDNS I created a single client - !MLDynDNS - which would be run as the connection started up, using the !ArmTCP dialler which did a lovely job of managing connections (for me anyhow). !MLDynDNS would send the very simple HTTP request to the Monolith servers to register my local IP address with the hostname (I believe I was '
gerphlet.dyn.ml.org'). It wasn't a particularly complex
program, but I know a few people used it.
!DynDNS When Monolith was shut down (which I believe was due to their servers crashing due to over use), I was pointed at
dyndns.org (which is still
very much alive!) and modified my scripts to point at it instead. The
protocol was almost identical if I recall rightly.
For simple little programs, they were quite configurable, providing options for local web proxies as well as (obviously) the credentials, debugging and even the program to launch once the configuration had been set. Well, I thought it quite neat.
When Chris and I were sharing a house at University, his machine had the external connection most of the time. My machine was networked, over Econet, and we could dial in to the University - there were only a few lines available for dial in, which made it quite fun to get a connection sometimes. The Internet stack, using EconetA on an A5000 wasn't great, but it worked reasonably well. However, at that time, there wasn't any support for NAT in the stack - that came about 9 years later! - so it was either routed traffic (which was a problem as there wouldn't be a return route) or proxying.
I think at that time !WebServe hadn't been released, so it wasn't even
possible to use a HTTP proxy. Other solutions did exist - I think that
and !DeltaNet had some proxying support,
but I was keen to do something myself. !JFProxy was my solution to the
problem - the idea was that one application could handle many different
types of proxy requests, with just minor modifications to the data being
passed through (sometimes none). The proxy handlers themselves were just
libraries which were configured through a
controlled where they listened and any configuration parameters.
Proxies like '
HTTP' and '
would just forward the connection to a
remote host that had been configured. Others, however, did a little more.
Prompt' proxy would ask for a host to connect to, and
on receiving a response from the user would connect to it - this was mostly
useful for telnet connections into the University. '
on the other hand would implicitly include authentication parameters in the
HTTP request so that you were always authenticated. I'm not entirely sure
why I did that, but I'm sure there was a good reason!
There was an experimental '
SOCKS 5' proxy, which worked pretty
well really. Although it didn't support dynamic listening, it did support
the connections through it.
There was also a '
POP' proxy which would allow you to log in
with one user name and depending on the user you gave might go to different
hosts (and use different names at those hosts). For example, it could be
configured that a connection for user '
go to the host '
mail.essex.ac.uk' and log in with the user
jrflet'. Multiple of these settings could be configured in a
special file. The result was that only one POP proxy need be set up, despite
there being multiple people connecting to different servers.
At some point I had wanted to update the '
HTTP' proxy to be
properly caching, but the amount of work that would require to get it right
was more than I could devote myself to. Then !WebServe came out, and the
whole issue was moot.
Each of the proxies were implemented in libraries, which both separated their functionality and made them easier to maintain. It just made a lot more sense at the time, and the things that I learnt from that implementation went into the later development of !JFTerm.
I'm not entirely sure why I wrote !Imagen. I do remember that for a long time it didn't have a name - as an image map editor I didn't really think of a name that captured it properly. I have a vague feeling that I came across references to the server side image map processing in !ArcWeb and wondered how to use it. The two major formats - NCSA and CERN - of the image map data weren't particularly different. Soon after I found that there were client side image maps as well, although if I remember rightly, these were only just being taken up.
According to the !Help file, the majority of the code was written over the course of about 3 days, and worked pretty well. The file also tells me that 'Kozzey' effectively made me write the application, just to show that I could. I knew that I used some code I found in a book which does 'point inside polygon' which was written in C and made it work with my program. I didn't remember how I worked out where the click was prior to that, though.
Apparently - so the !Help file tells me - the original method was quite horrid. When you clicked it would create a sprite the size of the region, convert the polygons in the image map to a Draw path and plot it to the sprite. It would then check the colour of the pixel where the pointer clicked. If it was set, you were in the polygon. Cringe. There was some fast reject based on the polygon bounding box but still... not great.
At the time I didn't know much about linking C with BASIC - which is a little amusing in light of what I would eventually do - so I placed the C code into a module and exposed the interface through a SWI. This made the checking of the code sufficiently fast that it could be done all the time that the pointer was in the window. It was fast, and simple, enough to allow me to include a status bar which showed the destination of the link the pointer was over.
I say it was amusing, because the code that was used in the 'Super Quick Guide To Linking C with BASIC' was exactly the polygon code that I had used in !Imagen.
!Imagen was also the first time I tried to do any software under a shareware license - if you like it, given me some money and I'll do you a proper 'registered' version and give you some better support. 'Better' is a problematic thing, because I'd probably just do the same thing as if you'd not registered, as I tend to want to help and fix things.
Anyhow, it wasn't great. I think I had one person register, and they were very nice - I provided the support for the things they suggested. But there was nobody else, so I gave up on the idea of doing any shareware things, and returned to just making the software I wrote available for free. I think there's a few reasons for that. It's a quite niche market and there are limited people who will actually pay for things.
Also, there's my general principle that I don't like to advertise myself and instead prefer people to find the things I do through word of mouth, or random searching. That doesn't really help if you want people to pay attention. Writing a couple of novel's worth of rambles about RISC OS but not really telling anyone that you're doing it other than a few friends is also a way to not get much attention .
I was quite pleased with !Imagen, although it did have some rough edges. It didn't feel quite so polished. Really it should have had an editing model closer to that of !Draw but I never really got around to doing that. Like many things it worked well enough.
I did a few silly things with it, like sticking a little application that would announce it starting with a big banner - which took longer than the main application took to load itself.
When we started using AMPlayer at RISCOS Ltd, I wanted to have a central music player that you could control. I tried writing a simple command line driven player. Back then I had a lot fewer MP3s and addressing them by fully specified path wasn't a big deal. It was a very simple tool that you just connected to and told it what you wanted to play. No queueing, no information, not even tab completion or anything nice like that.
Playing a track was something like:
*telnet localhost 77 Trying... Connected to loopback. Escape character is '^]'. Remote MP3 player, (c) Justin Fletcher Use .help for help, @ to catalogue. MP3s?@ 01/BeneathTheSkin. MP3s?.help Help: .ls <directory> : list directory @<directory> : list directory .help : this message .area <area> : change the area .quit : quit! <file> : play a track MP3s?@01/BeneathTheSkin 01/Violet'sDance/mp3 02/BeneathTheSkin/mp3 03/FallingUp/mp3 04/Deep/mp3 05/Black/mp3 06/Strange/mp3 07/DreamsAndIllusions/mp3 08/HaveFaith/mp3 09/Pandora'sBox/mp3 10/95And7/mp3 11/Deep(ChristAnalogueMix)/mp3 12/BeneathTheSkin(SubconsciousRemixByCevinKey)/mp3 MP3s?01/BeneathTheSkin.06/Strange/mp3 MP3s?.quit Closing connection Connection closed.
Mostly it as a demonstration of how you could make EasySocket do something useful, albeit not a very impressive demonstration!
The browsers for RISC OS included plug in support in almost all of the browser versions - even my own !Mozilla port did to a limited extent. The Plug In protocol was a relatively complicated set of Wimp messages modelled, in spirit, around the Netscape Plug In API. Having the plug in live inside its own application meant that it had no access to any part of the browser except that which was exposed by the Wimp protocol (notwithstanding the ability to use SWI Wimp_TransferBlock to directly access the application's memory).
In particular this meant that if your plug in crashed (as was often the case whilst you were developing it), the browser just saw it as an unexpected exit and tidied up without being otherwise affected (early versions of !Fresco excepted). Whilst RISC OS might not have had any other form of security, having a separate process for the plug in was a sensible move. Of course, it helped that the system as a whole didn't have a large amount of memory available, the application space was limited to 26MB and the system support for dynamic linking was nonexistent.
Anyhow, I wanted to try out support for different file formats as Plug Ins. Particularly, I wanted a vector file format, so that I wasn't restricted to bitmap images, and DrawFile was an obvious choice. All you needed to render a DrawFile was a single SWI call (SWI DrawFile_Render) - all the rest of the complexity was tied up in getting the data to the application.
I wrote a simple BASIC library, imaginatively called
whilst writing !DrawPlug, which provided all the interfacing necessary to
talk to the browser, and get data from it. Getting the implementation 'just
right' so that it was seamless was a bit of a fun task, but worked quite
well when finally executed within the browser. For example, the following
HTML produced a quite nice result - albeit not the most useful of pictures.
Later the work on the !DrawPlug application was applied to the more standardised SVG format. The Plug in code became the basis for the main !SVG application.