Direct messages, remembered aliases, and friends¶
Status: design, nothing built. Companion to CHAT-FEDERATION-DESIGN.md, which covers the trunks
this rides on.
What we are building¶
Send a message to one person, on this machine or another, without being in the same room - or in any room. Remember your alias between sessions. Keep a friends list.
The command shapes¶
Two prefixes, and the parallel is the point:
/command ... does something to your session (already true today)
@person message says something to one person (new)
anything else is said to the room (already true today)
So typed(0) = 47 means command, typed(0) = 64 means direct message, and everything else is
speech. The client already tests the first character for /; this is one more branch beside it.
Long and short forms, exactly as proposed:
/direct RONNY hello there the explicit form, reads well in /help
/direct D100!RONNY hello there ...qualified by machine
@RONNY hello there the short form people will actually type
@D100!RONNY hello there ...qualified by machine
Why ! for the machine and not @. @ is taken by the prefix. @RONNY@D100 hello is ugly and
needs a parser that counts @ signs. machine!alias reads left to right as route-then-person, is
one character, and has an honourable precedent in UUCP addressing from exactly this era. It also does
not collide with the : and ( ) that SINTRAN filespecs already use.
Display uses the same form, so what you read is what you can type back:
RONNY: hello everyone someone on your own machine
D102!KARI: hello from over here someone on another machine
*D102!KARI: are you free? a direct message TO you, marked so it cannot be missed
Duplicate aliases: the hard part, and the rule¶
Aliases are unique per machine - findByName already enforces that - and cannot be made unique
across machines without a central registry. Worse, as you say, two machines can each legitimately
have a RONNY long before they ever start talking to each other. There is no moment at which a
global rule could have been applied.
So do not try. Allow duplicates, and never guess who was meant.
@RONNY hello one RONNY in the federation -> delivered
two or more -> REFUSED, with the list
CHAT: which RONNY? D100!RONNY, D102!RONNY
The refusal is the feature. A direct message going silently to the wrong person is a privacy failure, not an inconvenience, and it is exactly the kind of quiet wrong answer this project has been bitten by elsewhere. Refusing costs one retype and cannot mislead.
AND EVERY DELIVERY SAYS WHERE IT WENT, ambiguous or not:
@KARI are you free?
CHAT: sent to D102!KARI
This is the other half of the same idea and it matters more than it looks. Refusing an ambiguous
name protects you when the client can SEE the collision; the delivery report protects you when it
cannot - a machine that has just gone Down, a second RONNY who logged in a moment ago, a trunk that
came back with a different user list. You are told the qualified name that actually received it,
every time, so a wrong delivery is visible immediately instead of days later. It costs one line.
Rejected: local-first. Delivering to the local RONNY when a remote one also exists is
convenient right up to the day you meant the remote one, and then your message went to a stranger
with no sign that anything was wrong.
Never renaming anyone retroactively. Forcing the second RONNY to rename when trunks connect
punishes whoever's machine happened to boot later, and the timing is arbitrary.
Delivering to someone in another room¶
Today the server's memberUsed / memberMagic / memberName table is flat, because there is one
room. Direct messages need a user who is not in your room, so the table becomes
server-scope with a room attribute, not per-room. That is a small change now and an awkward one
later, so it belongs in the first room-aware phase.
Delivery paths:
- same machine - look the alias up in the local table, send to that magic number.
- another machine - hand it to the trunk addressed
machine!alias; the receiving server looks the alias up locally and delivers. If that machine is not a direct neighbour it relays, which is the chain case already in the federation plan. - not logged in - refused, and said plainly. No store and forward. A message that waits for someone is a mailbox, which is a different product with different rules; SINTRAN already has mail for that. Say "not logged in" rather than half-implementing it.
The client config file¶
CHAT:CNFG in the user's own SINTRAN area - which is per-user by construction, so there is nothing
to configure about where it lives.
It is reachable from PLANC today. The runtime provides the monitor calls needed as ordinary
MONn routines: 50 open, 54 close, 1 inbt, 2 outbt. Nothing exotic, no interface
routine, no assembler.
Line-oriented, keyword then value, because it has to be editable by hand when there is no other tooling:
ALIAS RONNY
ROOM CHAT-LOBBY
FRIEND D100!OLAV
FRIEND D102!KARI
Rules that keep it pleasant:
- unknown keywords are ignored, not errors. A newer client's file must not break an older one.
- missing file is not an error - it means a first run, and the client asks for an alias or falls back to the SINTRAN user name.
- written back when something changes, so
/nick OLAVis remembered next time. That is the whole point: today the nickname is hard-coded toRONNYand the "what is not finished" note inCHAT.PLNCalready lists reading it from somewhere as an open item.
Seeing who is out there¶
Refusing an ambiguous name is only reasonable if you can find out what the choices are. Two commands, in the existing one-word style:
/machines the trunks, and whether they are up
/who everyone, qualified, grouped by machine
/who D102 just that machine
/machines
CHAT: D100 this machine 3 users
CHAT: D102 up 2 users
CHAT: D103 DOWN last heard 11.42
/who
CHAT: D100 RONNY, OLAV, KARI
CHAT: D102 KARI, SVEIN
Two people called KARI are visible at a glance, which is exactly when you need to know it - before
you type @KARI and get refused, not after.
/who finally has an answer. It exists in the client today and deliberately says
"NOT ON THE WIRE YET", because there was no query kind in the format. This is that kind, and the
same reply shape serves both commands: a list of machines, each with its users.
/machines shows the peer table from the federation design directly - system, state, last heard.
A machine that is Down still appears, because "D103 is off" is a useful answer and an empty list is
not.
Friends¶
/friends list them, showing who is on right now
/friend D102!KARI add
/unfriend D102!KARI remove
Aligned with the existing commands: one word, at most one argument, same as /join and /nick.
Friends are stored qualified, always - D102!KARI, never bare KARI - because an unqualified
friend is ambiguous the moment two machines have that name, and a friends list that silently points
at the wrong person is worse than no list.
Showing who is online needs presence, which needs federation. So the list can be stored and edited from day one, but "who is on" is gated behind the phase that exchanges user lists.
New message kinds¶
Three, and each needs a golden in both directions before it is built:
kDirect client -> server target machine, target alias, text
kDirGot server -> client from machine!alias, text
kDirectSent client -> ... server -> client, the qualified name it was delivered to
kDirectBad server -> client why it failed, and the candidate list when ambiguous
kWhoAsk client -> server optional machine filter
kWhoList server -> client machines, each with state and its users
kDirectBad carrying candidates is what makes the ambiguity rule usable rather than annoying.
Reminder from the /nick defect: the C# and PLANC ends share no code, so those bytes are the only
agreement, and an unpinned direction is where the two silently drift apart.
Order of work¶
Follows the federation phases rather than fighting them:
- Config file and alias memory - needs no server change at all, and can be built and proved on
one machine today.
/nickstarts persisting. - Local direct messages - the server-scope member table,
kDirect/kDirGot/kDirectSent/kDirectBad,@and/direct. Still one machine; ambiguity cannot arise yet, but the qualified syntax and the delivery report are there from the start, so nothing has to change later and the habit of reading "sent to X" forms before it matters./whoand/machinesland here too - trivial with one machine, and the reply shape is then already right when there are several. - Friends list, stored - qualified names, no presence yet.
- Remote direct messages - after federation phase C, when a server knows who is on other machines. Ambiguity refusal becomes real here.
- Friend presence - who is on, across machines.
Step 1 is worth doing first regardless of everything else: it is small, self-contained, needs no
trunk, and removes the hard-coded RONNY.