v3.00 Beta 10
~~~~~~~~~~~~~
* A share whose server is not there now says so in words worth reading.

  Double clicking a saved share for a machine that is switched off, or that
  has stopped sharing, used to report "Timed out while connecting" - true,
  and of no use to somebody who has just double clicked an icon.  It now
  names the machine and says what has almost certainly happened:

      FILESERVER is not answering.  It may be switched off, or it may have
      stopped sharing files.

  A name that nothing on the network answers to is reported separately, and
  says that it may be the name rather than the machine.  Neither is a change
  of behaviour - the connection failed before and fails now - only of what
  is said about it.  The underlying reason still goes to LanMan98$Log.

  The probe for the newer port is not covered by this.  It is expected to
  fail against a server that wants the older one, and stays quiet.

  The front end no longer answers it with the password, either.  Any failed
  connection used to reopen the connect window with the password ready to be
  retyped, which is the right answer to a refused logon and the wrong one to
  a machine that is switched off: it says the password was the problem while
  the message says it was not.  This one failure now carries a number the
  front end recognises, and is reported and nothing more; everything else
  behaves as it did.

* Dismounting a share left the directory watch running.  The thread and the
  block it scans into were not drained, and that block holds a pointer to
  the image that is freed a moment later.  The keepalive has always been
  drained; the watch is now drained with it.

v3.00 Beta 9
~~~~~~~~~~~~
* A circuit that could not be reopened left a freed one behind, which the
  tidy-up on the way out then read and freed a second time - a data abort.

  Connecting reopens the circuit each time it moves on to another way of
  asking: after an SMB2 attempt that got nowhere, before the older protocol
  is tried, and again between the two forms of the SMB2 negotiate.  Each
  reopen let go of the old circuit and then asked for a new one, and left
  the old pointer in place while it did so.  A machine that answered a
  moment ago and has stopped answering is exactly when the new one cannot
  be opened, and the pointer that was left behind is then used.

  Reported as a reproducible crash on clicking a saved share whose machine
  is switched off.  The field is cleared before anything that can fail now,
  which is how the reconnect path has always done it.

v3.00 Beta 8
~~~~~~~~~~~~
* A file whose name uses characters RISC OS has not got can now be opened,
  saved and renamed, rather than only looked at.

  Such a character used to be shown as an underscore.  That made a readable
  directory listing and an unusable name: an underscore is not what the
  server calls the file, so nothing could be done with it.

  It is now written as <ABCD, where ABCD is the character's UTF-16 value in
  hexadecimal, and read back the same way when the name is used.  A file
  whose name is two Chinese characters appears as something like
  <4E2D<6587, and opens.  The translation happens in both directions at the
  point the name crosses between the wire and RISC OS, so nothing above it -
  the Filer, an application's file dialogue, a command line - has to know
  anything about it.

  A character outside the basic plane, an emoji say, arrives as two units
  and is shown as two of these; reading them back gives the pair again.

  The marker is a "<" because that is already what a server's dollar looks
  like from RISC OS, and has been since long before any of this - so the
  notation costs nothing to carry and passes through that translation
  untouched.  A name that could itself be read back as the notation - a "<"
  with four hexadecimal digits behind it - has its "<" written out the same
  way, as <0024, so it reads back as itself.  A dollar anywhere else is
  left alone, so the recycle bin still looks like the recycle bin.

  This is SMB2 and above.  The older protocol is not asked for Unicode
  names and does not get any, so there is nothing there to translate.

v3.00 Beta 7
~~~~~~~~~~~~
* *Discover98 no longer aborts.  Reported from a user's machine as a trap
  handler error part way through discovery, with a register dump, which is
  what made it findable: the address landed in c.vc, the caller in c.smb2,
  and the register holding the connection pointed at a freed heap block.

  A connection record is made by smb_connect, which set only its circuit to
  NULL and left the rest as whatever the heap handed back.  Everything else
  is filled in as the connection is made, so a connection that fails part
  way leaves one field - the SMB2 connection - holding a leftover number.
  The tidy-up then reads it, finds something that is not zero, takes it for
  a live SMB2 connection and follows it into freed memory.

  The window needs the negotiate to succeed and the logon or the tree
  connect to fail, which is exactly what *Discover98 does over and over: it
  connects to every server it can find and most of them want credentials it
  has not got.  Before Beta 6 it found only the machines that announce
  themselves, so it rarely got the chance.  The record is cleared in full
  now.

* Discovery is a good deal quicker.  The two multicast questions used to be
  asked one after the other, each waiting out its own three seconds for
  answers that arrive in well under one.  They now go out together and one
  window collects the answers to both, which halves the fixed cost of every
  *Discover98 and *Servers98.

  What remains is per server: *Discover98 asks each machine it found what
  it shares, and Beta 6 finds a great many more machines than Beta 5 did.
  *Servers98 lists what is out there without connecting to any of it, and
  LanMan98$NoBrowse leaves out the one of the three questions that reaches
  furthest.

* Several places in the new browse code kept pointers in ordinary locals
  across the point an error returns to, and freed them afterwards.  What is
  in such a local after an error is whatever the compiler left in a
  register, so the failure showed up as a crash somewhere unrelated rather
  than where it was.  They are all declared volatile now, as the rest of
  the module already does.

v3.00 Beta 6
~~~~~~~~~~~~
* The network is now asked what is on it three ways rather than one, and
  *Discover98 and *Servers98 report what all three turned up.

  The question this client has asked since Beta 1 is the multicast one, and
  it is answered by Samba, by a Mac and by most NAS boxes.  It is not
  answered by Windows, which stopped answering anything of the sort when
  the Computer Browser service was retired, and it is not answered by a
  Samba built without a responder for it.  Those machines were perfectly
  reachable and completely invisible, and no amount of asking the network
  at large would turn them up.

  Two more questions now go with it:

  WS-Discovery, which is what Windows answers now.  A SOAP probe to
  239.255.255.250 and every machine that shares anything replies.  It costs
  one packet and asks nothing of the servers beyond the reply, so it runs
  wherever the multicast question runs.

  The browse list, which is what a workgroup's master browser keeps.  One
  name lookup finds it - it is the machine holding <WORKGROUP><1D>, or the
  domain controller at <1B> if there is no browser - and one call to it
  returns every server it has heard of, including ones on the far side of a
  router, which no multicast ever crosses.  This one costs a connection and
  a logon, and the call is RAP, which exists only in SMB1, so it is asked
  only by a command somebody typed and never on a timer, and a network
  whose servers have all turned SMB1 off simply has no browse list to read.

  A machine found more than one way is listed once.  LanMan98$NoMDNS,
  LanMan98$NoWSD and LanMan98$NoBrowse each switch one off;
  LanMan98$Workgroup says which workgroup to ask about, and falls back to
  LanMan98$Domain and then to WORKGROUP.


v3.00 Beta 5
~~~~~~~~~~~~
* A server that refuses an SMB 3.1.1 negotiate is now asked again without
  it, rather than being given up on.

  Offering 3.1.1 means filling in two fields - NegotiateContextOffset and
  NegotiateContextCount - which every dialect before it reads as
  ClientStartTime, and which it requires to be zero.  A server that
  predates 3.1.1 refuses the whole negotiate over that, and all it says is
  STATUS_INVALID_PARAMETER: nothing in the reply says what was objected to.

  Since Beta 3, where 3.1.1 arrived, that refusal was taken to mean the
  server does not speak SMB2 at all, and the older protocol was tried
  instead.  Where the server still had SMB1 enabled this showed only as a
  connection slower than it should have been.  Where SMB1 was turned off,
  which is most servers now, the mount failed outright - against a server
  the same client had connected to a few days earlier - saying there was no
  protocol left to talk to it with.

  The second attempt is the request this client sent before 3.1.1 was
  implemented at all: 2.0.2, 2.1, 3.0 and 3.0.2, no contexts, and those
  eight bytes zero.  It costs one more circuit and one more round trip,
  only against a server that has already refused once, and only when it
  answered in SMB2 to do the refusing.

* A refused negotiate now says that it was refused.  "Did not answer SMB2"
  and "answered SMB2 and said no" are very different things to be told when
  a mount has just failed, and the second one now carries the status the
  server sent.  The log records the refusal and the retry as well.

v3.00 Beta 4
~~~~~~~~~~~~
* The hourglass no longer appears when nobody has asked for anything.  It
  was raised around every wait for a reply from the server.  That is right
  for a filing system operation and wrong for the two things this module
  does on a timer: the keepalive, and the directory watch that notices
  changes made by other machines.  Both run from a callback, so the glass
  they raised landed over whatever the user was actually doing.

  Not a flicker, either.  The thread that asks parks inside the receive with
  the glass still up and is not serviced again until its reply arrives, so
  it stayed up for the whole round trip - and the watch re-reads a directory
  every five seconds, once per mount.

  It is now raised in the foreground and nowhere else, which is where
  somebody is waiting on the answer.  Nothing about what the module does on
  a timer has changed, only whether it says so; LanMan98$WatchPeriod and
  LanMan98$KeepAlive still set the two intervals.

* The !Run file said the network sweep was off unless asked for.  It has
  been on by default since Beta 3, and the line that says otherwise was
  corrected in the source tree's copy rather than in the one that ships, so
  the archive kept the old wording.  Both copies now say the same thing.

* The SMB2 bring-up scaffolding is out of the module.  SMB2SelfTest drove
  each operation against the connected share and described what happened,
  which was how the protocol work was checked before any of it went under
  the filing system; it has not been reachable since, from a command, a SWI
  or anything else, but it was still being compiled in.  With it goes
  LanMan98$SMB2Write, the variable that let it write a probe file to your
  server, which nothing else ever read.

v3.00 Beta 3
~~~~~~~~~~~~
* The network sweep is on by default, every five minutes, now that the
  fault it was implicated in is fixed.  A server switched on after the
  desktop started is noticed without anybody looking for it.  Set
  LanMan98$SweepPeriod to change the interval, or to 0 to switch it off.

* The network sweep no longer hangs the desktop.  This was the fault behind
  the report that *Discover98 hung and that connections stopped working
  afterwards, and it is why the sweep has been switched off by default
  since Beta 2.

  Answers to the sweep's question were unpacked in a loop that ran until
  the socket had nothing left.  That is harmless where the answers are a
  handful and arrive at once.  It is not harmless on a real network, where
  more can arrive while the last lot is being unpacked, and the loop need
  never end - and it runs in a callback, so the Wimp is not running while
  it is in there.  The desktop stops redrawing and stops answering, which
  looks exactly like a hung machine; whatever was in the foreground, a
  *Discover98 say, appears to hang with it.

  One call now unpacks at most eight answers and returns.  Both callers
  come back for more, so nothing is lost but the possibility of sitting
  there.  The original code read one answer per frame and was bounded by
  that; the bound went missing when the wait was turned inside out to let
  the sweep run in the background, and only shows on a network busy enough
  to keep the socket fed.

  Tested with the sweep set to six seconds - fifty times more often than it
  would ever run - against a network of five servers: the desktop kept
  redrawing throughout, *Discover98 finished in four seconds each time, and
  connections worked afterwards.

* A share kept somewhere other than Discs stays there.  Moving a saved
  share onto another disc, or into a directory with the rest of a group,
  and then using it, put a copy back into Discs every time.

  Connecting to a share writes its settings back, and where that was
  written was decided by "is this in Discs?": anything that was not got
  written into Discs under its local name.  That was meant for a share
  *Discover98 had just found, which it leaves in the scrap directory -
  connecting to one of those is what promotes it into Discs, and is what
  makes a share that was merely seen into one that is kept.  It caught
  every share the user had deliberately filed elsewhere as well.  Now only
  a share opened from the discovery directory is promoted; anything else is
  written back where it was.  With a handful of shares the old behaviour
  was untidy; with dozens it made them impossible to organise at all.

* Only one copy of the Filer runs at a time.  Starting it again - which is
  what installing a newer version amounts to - asks the copy already
  running to quit rather than adding a second icon to the bar, a second of
  everything on its menu and a second of every alert.  The mounts belong to
  the module rather than to the front end, so they stay up and the new copy
  reads them back as it starts.

* SMB 3.1.1.  The dialect ladder stopped one rung short; it no longer does,
  and 3.1.1 is what an unrestricted server now settles on.

  3.1.1 stops declaring what a client can do in a capabilities word and
  starts listing it: the negotiate carries a list of contexts, and two of
  them matter.  One says which hash protects the negotiation, the other
  which cipher encrypts the session - AES-128-CCM, which is what this
  client implements.  Without the cipher context a server may choose
  AES-128-GCM and nothing afterwards can be read.

  What the hash protects is the negotiation itself.  A running SHA-512 over
  every negotiate and session setup message becomes the context of the key
  derivation, so a listener that alters what was agreed makes the two ends
  derive different keys and the session fails, rather than the negotiation
  quietly settling on whatever the listener preferred.  The one message left
  out is the reply that completes the logon: the keys are settled from the
  value as it stood when the last request went, and the server does the same.

  SHA-512 is new here, in c/sha512, because nothing else needed it.  It is
  checked against a reference implementation over the padding boundaries
  where a hash usually breaks, and then on the machine itself, since a 64
  bit hash on a 32 bit compiler is exactly where the arithmetic would go
  wrong quietly.

  3.1.1 also renames the keys - SMBSigningKey, SMBC2SCipherKey and
  SMBS2CCipherKey - and takes their context from the hash rather than from
  a fixed string.  A 3.1.1 connection is signed whatever the server said
  about signing in the negotiate: the hash is only worth having if the
  messages carrying its result are signed, and a server sent unsigned
  requests refuses the tree connect with "Access denied" and says no more
  about it.

  LanMan98$SMB3 still means 3.0 and 3.0.2 only, which is now also the way
  to ask for a connection without 3.1.1.

v3.00 Beta 2
~~~~~~~~~~~~
* Traffic can be encrypted.  SMB 3.0 and 3.0.2 connections now negotiate
  AES-128-CCM, so filenames and file contents no longer cross the network
  in clear.

  Signing, which this client has done since 2.52, proves a message was not
  altered on the way; it hides nothing.  Every filename and every byte of
  every file was readable by anything on the path.  That is tolerable on a
  LAN and not tolerable anywhere else, which made it the thing standing
  between this client and a share reached across a wider network.

  A message is wrapped in a transform header and encrypted whole, so the
  header - which command, which file handle, how much data - is hidden
  along with the payload.  Only the negotiate and the session setup stay in
  clear, because they are what establishes the key.  An encrypted message
  is not signed as well: the tag over the whole of it already proves it was
  not altered.

  It comes on by itself when the server asks for it, either for the session
  or for one share - which is what makes shares configured to demand it
  reachable at all, where before the connection was simply refused.  Set
  LanMan98$Encrypt to insist on it even where the server would settle for
  less; a connection that cannot have it then fails saying so rather than
  quietly continuing in clear.

  Two keys are derived, one per direction, so a message this end sent
  cannot be replayed back as though the server had said it.  The nonce
  counts rather than being taken from a clock: counter mode fails badly if
  one is ever repeated under the same key.

  The CCM implementation in c/aes was checked against a reference
  implementation over 200 encryptions at the sizes and shapes SMB uses, and
  refused all 150 attempts to alter a message, its additional data or its
  tag.  End to end, a share with "smb encrypt = required" is refused by the
  previous release and mounts, reads and writes with this one; a packet
  capture of that session holds 83 encrypted messages and neither the file
  name nor its contents in any encoding.

* Waits and the keepalive can be set for a slower link.  The defaults are
  unchanged and suit a local network; three variables raise them for one
  that is not.

  LanMan98$KeepAlive is how often, in centiseconds, an idle connection is
  prodded so it stays up.  A hundred seconds is comfortable where nothing
  in the middle is counting, and is not comfortable anywhere else: a NAT or
  a stateful firewall forgets an idle mapping on its own schedule, and the
  shorter ones drop it well inside that.  The session is then gone without
  either end having said so.  Something around 3000 sits inside the usual
  mapping lifetimes, and a keepalive is one echo and its reply.

  LanMan98$Timeout and LanMan98$ConnectTimeout are how long to wait for an
  answer and for a circuit.  Twenty and ten seconds are generous on a local
  network, where a server either answers promptly or is not going to; a
  distant server's handshake can take several retransmissions first.  Both
  are read once when a circuit is made, not per message.

* One round trip saved on the last read of a file.  A read that comes back
  short of what was asked for is now taken as the end of the file, rather
  than asking again to be told END_OF_FILE.

  The server returns everything it has up to the amount requested, and this
  client never requests more than the server said it would accept, so short
  means ended.  Reading a ten byte file took two reads and now takes one.
  It is paid on every file that does not end exactly on a block boundary -
  invisible on a local network, and the length of the link away from it,
  which is why it is here rather than filed under tidying.

* A server that appears on the network is noticed.  A machine switched on
  after the desktop started, or one that joins the network later, is now
  found without anybody thinking to look for it, and its name is put in
  LanMan98$New for the Filer to show.

  *Discover98 has asked the network what is on it since 2.60, but only
  when a user thinks to ask.  The same question asked on a timer notices
  by itself.  It costs one UDP packet to a multicast address, and the
  answers come back unbidden, so a sweep needs no connection, no
  credentials, and nothing at the other end - which is why it is safe to
  leave running.

  Enumerating the shares each server offers is deliberately not done here.
  That needs a connection and a logon per server, and repeating it against
  every machine on the network every few minutes is how account lockouts
  happen; asking what a server shares stays where it was, on the user's
  own *Discover98.

  Nothing waits.  The question is asked, the callback returns to the
  machine, and each later callback takes whatever has arrived until the
  collecting period is up - so the desktop is never held while a sweep is
  in progress.  The wait inside DiscoverServers was turned inside out to
  make this possible, which leaves the foreground and the background
  collecting answers through one implementation rather than two that could
  drift apart.

  The first sweep after the list is empty only remembers what it finds:
  being told about every machine that was already there is not news.  The
  list is kept in LanMan98$SeenFile - by default <Choices$Write>.LanMan98Seen
  - so a reload does not announce the network all over again.

  Set LanMan98$SweepPeriod to the interval in centiseconds to turn this
  on; 30000, five minutes, is the sensible value.  It is off unless that
  is set.  Being the only part of this client that talks to the network
  by itself, it stays off until it has been proven on real hardware - a
  machine that does not ask for it behaves exactly as it did before.  The
  variable is looked at every ten seconds, so turning it on or off takes
  effect without a reload.

  The sweep is held off while a *command or a SWI is running, and a sweep
  part way through is abandoned when one starts.  The callback that drives
  it fires at any safe point, including inside a command that is itself
  part way through talking to a server, and the filing system's own
  in-use flag does not cover those - a command is not an entry to the
  filing system.  Without the hold a second socket could be opened, and
  read from, underneath one already in use.

  The Filer says so in a small window in the top right corner, which goes
  away by itself after fifteen seconds or when clicked.  Where the names
  will not fit the window it counts the servers instead: the desktop draws
  in a proportional font whose size is the user's business, so how wide a
  string is cannot be worked out from how long it is, and a list too long
  is otherwise centred and clipped at both ends.  Deliberately not
  an error box: Wimp_ReportError is modal and holds the whole desktop
  until somebody dismisses it, which for something nobody asked for -
  arriving mid-drag, or while the machine is unattended - is worse than
  saying nothing.  The window comes from a new "alert" template, and a
  !LanMan98 whose Templates predates it simply never shows one rather
  than failing to start.

* A directory changed by somebody else is noticed.  A file another machine
  adds to, changes or removes from a share now appears in, or disappears
  from, an open Filer window without the window being touched.

  FileSwitch already announces every change this machine makes, which is
  why a local save has always shown up; nothing announces a change made
  elsewhere.  Nor is there anything to listen for on the wire - SMB2's
  CHANGE_NOTIFY is an asynchronous request, and every request this client
  makes is synchronous - so the directory a viewer was last opened on is
  re-read on a timer and compared with what it held before.  A difference
  raises the same UpCall FileSwitch would have raised, which the Filer
  cannot tell apart from a local change.

  The scan is a thread serviced from a callback, exactly as the keepalive
  is, and shares the one connection with it.  Anything in the foreground
  drains it first, which costs at most one round trip rather than a whole
  enumeration because the scan gives up between entries rather than only
  at the end.

  Set LanMan98$WatchPeriod to the interval in centiseconds; the default is
  500, and 0 switches the whole thing off.  One directory per mount is
  watched - the one most recently listed, which is the one a viewer is
  showing.

v3.00 Beta 1
~~~~~~~~~~~~
* The version this work is released at.  Everything below is how it was
  arrived at, from 2.18 onwards; there is no change in behaviour between
  2.77 and this.

  The client speaks SMB2 and SMB3, authenticates through NTLMSSP, signs its
  messages, connects on port 445, finds servers and their shares by asking
  the network, reaches a machine without an account on it, converts names
  through the RISC OS alphabet, and prints.  The older protocol remains for
  servers that offer nothing else.  Nothing needs setting up.

* Attribution.  The source and !Help are Copyright RISC OS Developments
  2019+, credited to the RISC OS One Project.  The banner the module prints
  on loading names RISC OS Developments.

v2.77
~~~~~
* A machine can be reached without an account on it, which is what guest
  sharing on a Mac is, and what a share list from somebody else's machine
  needs.

  Given no user name, this used to offer an empty one, which a server
  refuses exactly as it refuses any name it does not know - so a Mac with
  guest sharing switched on answered "Logon failure" and its shares could
  not even be listed.  No name now means no name: the connection asks to be
  let in as nobody, which is a different request and one that a server
  allowing guests grants.

  Such a session is never signed, in either direction.  The key that signs
  a session is derived from the password, and there was not one, so neither
  end can sign whatever the server said it required when the connection was
  made - and a Mac does ask for signing and then hands out an unsigned
  guest session.  Servers are supposed to say so in the session flags and
  some do, but Samba returns nothing there for a session it let in
  anonymously, so this end goes by what it knows it sent rather than by
  what it is told.

* Discover tries a machine that refuses the name it was given a second time
  without one, rather than passing over it.  A machine nobody is logged on
  to usually still says what it shares.

* Discover says why a machine would not answer, rather than only that it
  did not.  "Would not say what it shares" covered a refused password, a
  machine that does not do this at all, and a machine that had gone away,
  which are three different things to do something about.

v2.76
~~~~~
* Files can be opened on a 26 bit RISC OS again.  This is the "buffer
  error" that made double clicking a file fail on VirtualRPC.

  Opening a file told FileSwitch to use a 4096 byte buffer.  FSEntry_Open
  is documented as returning "0 if file unbuffered, else must be a power of
  2 between 64 and 1024", so 4096 was never allowed.  RISC OS 5 does not
  check, so it worked there and only there; a 26 bit RISC OS does check and
  refused the open with error &412, "Bad buffer size".

  The refusal came after this filing system had already said the open had
  succeeded, which is why it looked so strange from the outside: the file
  opened, reported the right size, and was then never read from and never
  closed, and every application that opened a file said the same unhelpful
  thing.  A log of it showed opens with no reads after them at all.

  It now reports 1024, the largest the specification allows.  The allocated
  size that goes with it is rounded up to whatever the buffer size actually
  is, rather than to a fixed figure, since it is required to be a multiple
  of it.

* New system variable LanMan98$BlockSize sets that buffer size, for a
  machine that wants something else.  Zero means the file is not buffered
  by FileSwitch at all.  Anything that is not a power of two between 64 and
  1024 is ignored.

* Servers can be reached by name as well as by address, including the
  .local names that a Mac, a Synology or a QNAP announces itself under.

  A name is now looked for in three places rather than one: the name
  server, then the announcements every machine on the network makes about
  itself, then NetBIOS.  A name ending in .local goes straight to the
  announcements - that domain is set aside for them, and asking a name
  server about it only means waiting out a question that cannot be
  answered, which is what used to happen.  A name that resolves nowhere is
  handed on as it always was.

v2.75
~~~~~
* Corrects 2.73 and 2.74, which fixed the data loss but broke making a new
  file.

  The open was changed to FILE_OPEN, which never truncates - the point of
  the fix - but also never creates.  FileSwitch asks for "create and open"
  and for "open for update" through the same entry point and the library
  below reduces both to one flag, so an open that was meant to make a file
  could no longer make it: OPENOUT on a name that did not exist yet failed
  with "File not found", and anything saving through that route failed with
  it.

  It now asks for FILE_OPEN_IF when writing - open what is there, create
  what is not, truncate neither - and FILE_OPEN when only reading.  That is
  both halves at once, and it is what the older protocol has always done.
  Where a file is genuinely being replaced the length is set afterwards, as
  it always was; that is what shortens a file, not the open.

  Anyone on 2.73 or 2.74 should update.  Neither destroys files, but both
  fail to create them in this way.

* Known: a name containing a character the RISC OS alphabet has not got
  does not survive being written and read back - it returns as an
  underscore - so creating one leaves a second, differently named file
  beside it.  This can only happen for the seven positions RISC OS leaves
  undefined and for characters a server holds that RISC OS cannot show.

v2.74
~~~~~
* Discover no longer keeps every share it finds.

  It wrote a file into !LanMan98.Discs for each share on the network, which
  put every machine anybody happens to be running onto the local disc,
  permanently, whether or not it was ever wanted.  What is found now goes
  into the scrap directory instead and is cleared out at the start of each
  look.  A share becomes a kept icon in Discs when it is double clicked and
  the connection succeeds - not before.

  A share already kept is left alone and not offered again, as before: it
  may have a password in it, and finding it a second time is no reason to
  throw that away.

  The path is left in LanMan98$Found, which is what the icon bar menu opens
  after a look.  Where there is no scrap directory to use, the old place is
  used rather than failing.

v2.73
~~~~~
* DATA LOSS FIXED.  Opening a file for writing over SMB2 destroyed it.

  A file opened for update was opened with FILE_OVERWRITE_IF, which tells
  the server to truncate the file to nothing and start again.  Wanting to
  write to a file is not wanting to destroy it first, and nothing had to be
  written for the damage to be done: opening was enough.

  Anything that opens a file to modify part of it lost the contents that
  way.  An archiver is the obvious one - opening a Zip to look inside it
  opens it for update - so archives on a share emptied themselves on being
  looked at.  The damage was quiet rather than obvious, because the length
  was still cached from before the open: on close the extent was set back
  to what it had been, so the file came out its original size and full of
  zeros rather than visibly missing.  A run of zeros is also a well formed
  empty tar archive, which is why such a file was then shown as an empty
  archive and retyped Tar.

  Opening now asks for FILE_OPEN whether or not writing was wanted, which
  is what the older protocol has always done - its open sets OpenFunction
  to 1, "open the existing file".  So this was true over SMB2 only, which
  is why it has surfaced now.  Creating a file is a different call, and
  truncating one is a different call again; neither belongs in an open.

  Files already emptied cannot be recovered from this end - they are zeros
  on the server.  Restore them from a backup or from another copy.

* A read that is answered with nothing at all, at a position where there
  ought to be data, is noted in the log rather than passing silently as
  zeros.  Zero filling the tail of the last block of a file is ordinary and
  is not remarked on; being handed nothing on the first try is not, and a
  caller cannot tell those zeros from a file that really is zeros.

v2.72
~~~~~
* Names are converted through the RISC OS alphabet rather than a byte at a
  time, so the characters at &80-&9F survive a round trip over SMB2.

  SMB1 carried a name as bytes and a RISC OS machine could put its own
  bytes on the wire unaltered.  SMB2 carries names as UTF-16, so every one
  has to be converted - and the conversion is not the identity it was being
  treated as.  &A0-&FF are Latin-1 and did come out right by accident, but
  &80-&9F are where RISC OS keeps the Euro sign, the W and Y circumflexes,
  the curly quotes, the dashes, the OE ligature, the daggers and the fi and
  fl ligatures.  Latin-1 spends that range on control codes, so each of
  those thirty-two characters went to the server as a control code, and a
  name coming back the other way that used one arrived as a full stop -
  which RISC OS then read as part of the path.

  Both directions now go through the alphabet.  A character the alphabet
  has not got - most of Unicode - is shown as an underscore rather than a
  full stop; the name then does not match the server's, so such a file can
  be seen but not opened, which is as much as a fixed alphabet can do, but
  it no longer breaks the path it appears in.  Characters outside the basic
  plane arrive as one underscore rather than as two halves of one.

  The table is the one LanManFS uses, so a name written by either client
  reads the same in the other.  All 249 defined characters round trip; the
  seven positions RISC OS leaves undefined go out as U+FFFD, and the C1
  control codes are deliberately not mapped back - their byte values belong
  to something else here.

  Spaces are unaffected: the RISC OS hard space has always been translated
  to a space by the layer above this one, and still is.

* The log records what FileSwitch is told when a file is opened - the
  length, the allocated size, whether the file is readable and writable,
  and the block size - since a fault that never reaches the wire is a fault
  in one of those numbers.

v2.71
~~~~~
* SMB2 is now what is tried first, falling back to the older protocol only
  if the server will not answer it.

  It is what every current server offers, several of them offer nothing
  else, and everything the older protocol could do - printing was the last
  of it - now works over it.  Trying the old one first meant the common
  case took the worse of the two, and a server that refused it outright
  looked broken rather than modern.

  The highest dialect both ends know is used, which today means SMB 3.0.2.
  Nothing needs setting for this.

* Three new system variables hold the connection to one protocol level:

    LanMan98$SMB3   offer 3.0 and 3.0.2 only
    LanMan98$SMB2   offer 2.0.2 and 2.1 only
    LanMan98$SMB1   do not offer SMB2 at all

  Setting one settles the matter.  The level asked for is the level used,
  or the connection fails saying why, and nothing falls back to something
  else - so what a server does at each level can be found out one level at
  a time.  Nothing needs setting to connect normally.

  LanMan98$SMB2 used to mean "try SMB2 before the older protocol", which is
  now what happens without being asked.  It now means SMB 2.x and no
  higher.  A machine that sets it to reach a server which needed SMB2 will
  still reach it.

* New system variable LanMan98$NoSMB2 goes back to the old order, for a
  server that answers SMB2 and then handles it badly.

* New system variable LanMan98$SMB2Only refuses the fallback altogether: a
  connection either uses SMB2 or says why it could not.  Without it a
  server quietly dropping to the older protocol cannot be told from one
  that never tried, which makes it awkward to be sure what a machine is
  actually doing.  It is meant for finding that out rather than for
  everyday use.

* A machine that will not answer while looking around the network is moved
  past quickly rather than waited on.

  The waits everywhere else suit a connection somebody asked for: twenty
  seconds for an answer is worth it if the alternative is failing a mount
  that would have worked.  They do not suit looking around, where several
  machines are asked and some are not going to answer at all.  Looking is
  now impatient - two seconds - and the port each machine announced is used
  rather than trying one and then the other.  Five machines, three of which
  refuse, went from about a minute and a half to eight seconds, three of
  which are spent waiting for the announcements themselves.

* "Discover" no longer opens a task window of its own.  What it had to say
  is said by the icons appearing, and a window that has to be dismissed
  afterwards is one more thing to do rather than one less.  The pointer
  shows it is busy while it runs, and the directory opens when it stops.

* Servers and their shares can be found rather than typed in.

  Choosing "Discover" from the icon bar menu asks the network what is on
  it, asks each machine that answers what it shares, and leaves an icon in
  !LanMan98.Discs for every share that can be connected to.  Double
  clicking one opens the connect window with the server and share already
  filled in, wanting only a password - which is what that window has always
  done for a share saved by hand.  A share that already has an icon is left
  alone, so a password kept in one is not thrown away by looking again.

  Three commands do the work and can be used on their own:

    *Servers98 [<seconds>]
        Lists the file servers that announce themselves on this network.

    *Shares98 <server> [<user-name> <password>]
        Lists what one server shares, with what each is for.

    *Discover98 [<user-name> <password>]
        Both of the above, leaving an icon for each share found.

  Finding servers uses the announcements machines already make about
  themselves - which is how a Mac, a Synology or a QNAP turns up in
  somebody else's list without being configured anywhere.  The question is
  asked from an ordinary port, so the answers come back to this machine
  alone and nothing has to be joined or listened to.

  Listing shares is a remote procedure call carried on a named pipe, which
  is the only way to ask a server that no longer speaks the older protocol.
  It needs SMB2; there is nothing to ask on a connection without it.

* New system variable LanMan98$DiscoverAddr.  Set to an address, servers
  are asked there instead of being asked for at large, which is what to do
  on a network that will not carry a question addressed to everybody.

* A directory read over SMB2 asked for sixteen kilobytes at a time whatever
  the server had said it would send, and whatever the packet buffer could
  actually hold.  Both of those were being ignored, and they are not the
  same limit.

  A server that advertises less than that refuses the request outright, so
  the listing failed with "Invalid parameter".  A machine whose heap would
  not stretch to the buffer the connection asked for - the transfer sizes
  are settled first, and it settles for what it is given - then received a
  reply it had nowhere to put, and reported that instead.  Either way the
  share mounted and then would not list, which is a confusing way to fail.

  The request is now the smallest of what was wanted, what the server said
  it would send, and what will fit in the buffer that was actually got.
  The size the server gave for this has been read since SMB2 support was
  written and was never used for anything.

* New system variable LanMan98$PacketDump.  Set to a directory path, with a
  trailing dot, it writes every message sent and received into that
  directory as it goes - Out1, In1, Out2 and so on.  The capture was always
  in the code and there was no way to switch it on; there is now, which is
  what it takes to look at a server that cannot be reached to be tried.

* New system variable LanMan98$Log.  Set to a file path, an account of what
  the connection did is written there as it happens.

  It is meant to be sent to somebody who can read it.  A packet dump says
  what went over the wire and nothing else, which is no help at all when
  the complaint is that nothing went over the wire - a file that opens and
  then will not read leaves a dump that simply stops, with no way to tell
  whether the machine never asked for the data or asked and was refused.

  The log has both sides of that boundary in it: the server and share
  connected to, the dialect settled on and whether it is signed, the
  transfer sizes the server offered and the smaller ones actually used, the
  size of the buffer asked for and the size obtained, every file opened
  with the length and the allocated size reported back for it, every read
  and write the machine asks for with its position and length, how each was
  cut to fit if it was, one line for every message in each direction with
  its command and any error status, and - the point of the whole thing -
  any error at the moment it is raised, with its text and number, so the
  log ends at the failure rather than near it.

  It appends, so a file kept across several attempts holds all of them.  It
  writes a line at a time and closes the file each time, which is slow and
  is deliberate: a machine that stops dead still has everything up to the
  point where it stopped.

* The negotiate is padded to a multiple of eight bytes.  Nothing follows the
  dialect list to need the alignment, but every other client sends it that
  way, and a server is more likely to have been tried aligned than not.

* Printing works over SMB2 and SMB3.

  SMB2 has no print command.  The one SMB1 used - open print file, write,
  close - was dropped from the protocol, and nothing has implemented it in a
  very long time.  A share that spools now takes a job the way a disc share
  takes a file: create it, write the data, close it.  The name given is what
  the queue shows.

  Two things had to change beyond that.  A print job is opened asking only
  for write access, because a share that spools has nothing to read back and
  a server may refuse an open that asks for more than it can give.  And a
  print job is no longer cut to length after the event.

  That last one also fixes printing over SMB1.  The layer above treats a
  printer as a file: it writes whole buffers and then says how much of the
  last one was real.  For a file that is right, and the file is cut to that
  length afterwards.  A share that spools has no length to set - it answers
  that the path is invalid - so the padding at the end of the last buffer
  was going to the printer as rubbish, and on SMB1, where the old way of
  setting a length was a write of nothing, jobs came out cut short instead.

  The last block written to a print job is now held back rather than sent.
  The next write releases it; the call that sets the length releases it cut
  to size.  Only one block is ever held, because only the last one is ever
  short.  Jobs now arrive byte for byte, on both protocols, signed or not.

* A directory read over SMB2 stopped part way through, so a share showed
  only its first few dozen entries and anything made in it afterwards - a
  new folder, say - appeared not to exist even though the server had it.

  The layer above duplicates an object part way through a walk and then
  carries on with the copy.  The SMB2 side deliberately did not pass the
  walk to a duplicate, on the grounds that two objects sharing one open
  directory handle would close it twice; the duplicate therefore had
  nothing to continue from and reported the directory as finished.  Where
  it stopped depended on how many entries the caller asked for at a time,
  which is why small directories looked correct and large ones did not.

  A duplicate now inherits the walk the way the SMB1 side has always done
  it: it takes its own copy of the entries already fetched, keeps its own
  position in them, and shares the open handle under a reference count, so
  whichever object finishes last is the one that closes it.

  The suite gained a step for this.  It only ever built a directory with a
  single file in it, and a directory small enough to arrive in one reply
  proves nothing about the ones that do not - which is how this went
  unnoticed.  Step 8 now makes two hundred entries, lists them back and
  counts them.

* SMB 3.0 and 3.0.2 are now offered as well, and signed for.

  The 3.x family signs differently from 2.x: AES-CMAC rather than
  HMAC-SHA256, and under a key derived from the session key rather than the
  session key itself.  The derivation is the counter mode construction of
  SP800-108 with HMAC-SHA256, one iteration, 128 bits out.

  The label and the context in that derivation each carry their own
  terminating zero and are also separated by the zero byte the construction
  puts between them, so two zeros follow the label.  That is not obvious
  from reading the specification, and was settled by reproducing a real
  server's signature rather than by guessing.

  Which of the two is used follows the dialect, so a server capped at 2.x is
  signed to exactly as before.  Signing is still only used when the server
  requires it, or when LanMan98$Sign asks for it.

  3.1.1 is deliberately not offered.  It needs the negotiate contexts and
  the pre-authentication hash chain, and offering a dialect that cannot then
  be satisfied is worse than not offering it.

  Not implemented: the FSCTL_VALIDATE_NEGOTIATE_INFO exchange that 3.x uses
  to confirm afterwards that the negotiate was not tampered with.  Signing
  covers everything after the session setup; without this, a listener able
  to alter the negotiate could still clear the bit that says the server
  requires signing, and neither end would notice.

  AES on a slow machine is not free - a sixty kilobyte transfer is some
  thousands of block encryptions - which is another reason signing stays off
  unless it is wanted.

* A server that will not speak SMB1 at all is now reached over SMB2 without
  being asked to.

  Such a server answers the negotiate with a dialect index of 0xFFFF - "none
  of the ones you offered" - which this used to report as "Protocol index out
  of range", an error that says nothing about what is wrong or what to do
  about it.  Every current Windows answers that way, and so does any NAS
  hardened the same way.  There is nothing to fall back to at that point, so
  SMB2 is now tried whether or not LanMan98$SMB2 is set; if that fails too,
  the message says plainly that the server has SMB1 turned off.

  LanMan98$SMB2 still means what it did: prefer SMB2 from the start.  This
  only changes what happens when SMB1 is impossible.

* Messages can now be signed, in both protocols, so a server that insists on
  signing is reachable.  That was the last thing standing between this and a
  Windows share, and it is what SMB 3.x would have to be built on.

  SMB1 signs with MD5 over the key followed by the message, the signature
  field holding the sequence number while the digest is taken.  SMB2 signs
  with HMAC-SHA256 over the whole message, keeping the first sixteen bytes of
  the thirty-two.  Both use the session key the NTLMSSP exchange produced,
  which is why signing needs the extended security session setup and is not
  offered for the older schemes.

  Neither protocol signs the session setup itself.  The key that would sign
  it is the thing the exchange is establishing, and a server handed a signed
  request for a session it has not created yet drops the connection.  The
  reply to the last leg is signed, though, and it is checked: that is what
  proves the server derived the same key, and without it anything in the
  middle could clear the signing bits in the negotiate unnoticed.  After
  that every message is signed and every reply is required to carry one.

  Signing is used when the server requires it, and otherwise not: it costs a
  digest over every byte transferred, which on a slow machine is a real part
  of the transfer time and buys nothing on a network you trust.  A server
  that merely offers signing turns it on only for a client that asks in the
  negotiate, so asking is what the new LanMan98$Sign does.

* A signature that does not check out abandons the connection, and every
  later use of it fails at once.  The sequence is lost at that point and
  what is on the wire cannot be trusted anyway, so there is nothing useful
  left to say to that server.  Without this the tear-down that follows the
  failure blocks on a reply it will never understand, and takes the desktop
  with it.

* New system variable LanMan98$Sign turns signing on for every connection,
  including servers that would have settled for none.

* Authentication now goes through NTLMSSP, carried in the security blob of
  an extended security session setup, rather than putting an NTLMv2 response
  straight into the request.

  The older way is what Samba calls "raw NTLMv2", and it has been refused by
  default since Samba 4.5: the server answers STATUS_INVALID_PARAMETER and
  the mount fails with "Invalid parameter".  Every current Linux NAS is
  affected - Synology and QNAP among them - and the failure looks like a
  bad password rather than an unsupported scheme, because the older schemes
  the client fell back to are refused as well.

  Two flags have to be asked for in the negotiate itself for this to work,
  and both are now set there.  Extended security is only offered to a client
  that requested it in the negotiate; and the scheme a server answers a
  session setup in is the one the negotiate established, so without the NT
  status flag the interim reply carrying the challenge comes back in the DOS
  scheme, which has no code that stands for "more processing required".

  The first leg of the exchange sends a user identifier of zero.  The header
  otherwise still carries whatever the negotiate left in it, and a server
  asked to start a session under an identifier it never issued answers
  ERRbaduid.

  Nothing else changed: the NTLMSSP messages are the ones the SMB2 support
  already builds, so both protocols authenticate identically.  A server that
  does not offer extended security still gets the old NTLMv2, NTLMv1 and LM
  ladder in turn.  LanMan98$NoExtSec goes back to the old way.

* SMB can now be carried directly over TCP on port 445, as well as over the
  NetBIOS session service on port 139.  Connections try 445 first and fall
  back to 139, so servers that no longer run NetBIOS over TCP - which is the
  default on current Windows, macOS and Samba - are reachable without any
  configuration.  A connection made on 445 sends no NetBIOS session request,
  so the server name need only resolve to an address; it no longer has to be
  a NetBIOS name the server answers to.

* The port may be pinned per connection by appending it to the address in
  the angle brackets after the server name, as SERVER<address:port>.  The
  address may be omitted, as SERVER<:port>, to name a port while still
  looking the server name up.  A mount reported back to OmniClient keeps a
  port given this way, so saved mount links reconnect on the same port.
  Printer connections have nowhere to write a port - a printer is named
  through a special field, which ":" terminates - so they take the automatic
  choice, or LanMan98$Port.

* New system variable LanMan98$Port pins the port for every connection that
  does not name one of its own.

* Port 139 is what selects the NetBIOS transport.  Any other port named is
  taken to carry SMB directly, as 445 does, so a forwarded or tunnelled port
  behaves the same way the port it forwards to does.

* Reconnection after a dropped link now reuses the port the connection was
  established on, rather than always using 139.

* 32 bit NT status codes are now requested from any server that offers
  CAP_STATUS32, and are set on every request as the protocol requires.  The
  DOS-style error class and code pair they replace cannot distinguish an
  access denial from a bad password from a sharing violation, which made a
  failed connection almost impossible to diagnose.  Errors now name the
  status the server sent, for example "Logon failure: check the user name
  and password (NT status 0xC000006D)".

* Each NT status is mapped back to the DOS class and code it stands in for,
  so the error numbers the filing system tests against are unchanged
  whichever scheme the server answered in.  A status with no mapping is
  reported by number and given ERRSRV with a code of zero, which nothing
  tests for - in particular it cannot be mistaken for ERRSRV/ERRerror, which
  drives the transaction retry loop.  Responses are decoded according to the
  scheme the response itself declares, not the one that was asked for.

* Asking for NT status takes two things, not one: the flags2 bit on every
  request, and CAP_STATUS32 in the client capabilities of the session setup.
  A server told only through flags2 goes on answering in the DOS scheme,
  because what it records for the session is what the client declared in the
  session setup.  Both are now sent.

* New system variable LanMan98$NoNTStatus goes back to the old error scheme,
  for a server that offers the capability and then mishandles it.

* NTLMv2 authentication ([MS-NLMP] 3.3.2) is now offered first, falling back
  to NTLMv1 once if the server refuses the logon.  NTLMv1 is refused by
  default by Samba since 4.5, by Windows above LmCompatibilityLevel 2, and
  by macOS since Sierra, so it alone could no longer reach a current server;
  the fallback keeps the older NAS boxes that predate NTLMv2 working.  Only
  an authentication refusal falls back - a dropped line or a malformed reply
  is reported as it stands rather than retried and reported less usefully.

* The LM slot now carries an LMv2 response rather than the old DES one when
  NTLMv2 is in use.  Servers with lanman auth disabled, which is the default
  everywhere, reject the old LM response on sight.

* New files c.md5 and h.md5 (MD5 and HMAC-MD5), and c.ntlm and h.ntlm (the
  NTLMv2 and LMv2 responses).  The MD5 is the same public domain
  implementation, by the same author, as the MD4 already used for the NT
  password hash.  DateSecondsToFileTime has been added to c.date for the
  timestamp inside an NTLMv2 response; it is the inverse of DateTimetoSMB
  and does its 64 bit arithmetic the same way, in 32 bit halves.

* New system variable LanMan98$NTLMv1 skips NTLMv2 entirely, and
  LanMan98$Domain sets the domain to authenticate in.  The domain is both
  sent to the server and folded into the response, as it must be.

* Server names are now looked up through the naming service before NetBIOS
  is asked, which is the order Samba has long used.  A name that cannot be a
  NetBIOS name - one containing a dot, or longer than fifteen characters -
  skips the broadcast altogether, so "server.local" and "192.168.1.5" are no
  longer broadcast onto the network as NetBIOS names, which could never have
  produced an answer.  Measured on a network where nothing answers NetBIOS,
  that takes a failed lookup from 0.9 to 0.4 seconds; putting the naming
  service first costs nothing measurable, because a name the resolver does
  not know is refused immediately rather than timing out.

* New system variable LanMan98$NetBIOSFirst puts NetBIOS back in front.  It
  does not reinstate the broadcast for names that cannot be NetBIOS names.

* Directory listings now ask for SMB_FIND_FILE_BOTH_DIRECTORY_INFO, and a
  query about a single file for SMB_QUERY_FILE_ALL_INFO, whenever the
  dialect is NT LM 0.12.  Both carry a FILETIME where the old level carried
  a DOS date and time, so a timestamp no longer loses its odd second on the
  way across - the DOS format stores seconds in units of two.  Both levels
  had to move together, because the probe that works out whether a server
  reverses its DOS date and time compares what a find returned against what
  a query returned, and that only means anything when the two come from the
  same kind of clock.  LanMan98$FindStandard asks for the old levels back.

* Reads and writes now use READ_ANDX and WRITE_ANDX in place of the core
  read and write pair, claiming CAP_LARGE_READX and CAP_LARGE_WRITEX where
  the server offers them, and growing the message buffer to suit.  A 200K
  file moved in about 390 requests of 512 bytes; it now moves in four of up
  to 60K.  On a link with no appreciable latency that makes no difference to
  the time taken, which was measured; on a real network it is 390 round
  trips that no longer happen.  LanMan98$NoReadX returns to the old pair.

* The block size the filing system advertises has gone from 512 bytes to
  4096.  That is what decides how much the layer above asks for at a time,
  so it, rather than the SMB command in use, was the real limit on how many
  round trips a file cost.

* Fixed FsysGetSize, which was meant to round a file's length up to a whole
  block and instead returned the length modulo the block size: the + bound
  tighter than the &, and the mask was not inverted.

* The beginnings of SMB2.  New c.smb2 and h.smb2 negotiate the 2.0.2 and
  2.1 dialects, authenticate with NTLMSSP in new c.ntlmssp and h.ntlmssp,
  and connect to a share.  This is what reaches a server that will not
  speak SMB1 at all, which is now the default on Windows and macOS.

  The file operations above it - create, close, read, write, directory
  enumeration - are NOT implemented, so a connection made this way can be
  established but not used.  It is therefore behind LanMan98$SMB2 and off
  unless that is set; nothing changes for anyone who does not set it.  A
  server that does not answer SMB2 leaves the circuit in an unknown state,
  so the fallback to SMB1 reopens it rather than reusing it.

  Message signing is not implemented either, and the 3.x dialects are
  deliberately not offered, because a dialect cannot be offered and then
  not satisfied.  A server that requires signing is refused with an
  explanation rather than a failure further along.

* The SMB2 file operations - create, close, read, write and directory
  enumeration - are now written and exercised.  Directory entries come back
  as FileBothDirectoryInformation, which is the same layout the SMB1 find
  returns, so the decoder already in c.lm2 reads them unchanged.  A handle
  is now sixteen bytes rather than two, so it is carried as itself rather
  than packed into an int.

  SMB2SelfTest drives all of them against the connected share and reports
  what happened.  Against Samba: eight entries listed, a file read whole,
  and with LanMan98$SMB2Write set a file written and read back identical.

* SMB2 is now under the filing system.  New c.smb2fs and h.smb2fs fill in
  the same function table in h.smbsvr that c.lm2 fills in for SMB1, so the
  object model, the directory walk and the RISC OS entry points above it
  are unaware of which protocol is underneath.  A share can be mounted,
  listed, walked into and read from over SMB2.

  Directory enumeration holds its handle open across the walk, where SMB1
  could hand back a search identifier and forget about it, so an object now
  owns a handle that is closed however the walk ends - including when it is
  abandoned part way.  A duplicated object deliberately does not inherit
  the walk, since two objects sharing one handle would close it twice.

  Names arrive as UTF-16LE.  Anything outside the range this filing system
  can represent becomes a full stop rather than a stray byte, which is a
  placeholder until proper conversion is done.

* Writing over SMB2 now works as well: creating files and directories,
  writing to them, renaming, moving, deleting, setting a file's extent and
  writing dates and attributes back.

  SMB2 has no delete request.  A file is opened with delete access, marked
  so that closing the handle takes it away, and closed - so the operation
  that removes a file is, on the wire, a create.  Renaming is a set of
  information against an open handle rather than a request of its own, and
  because it replaces its target, a move no longer has to delete first the
  way the older request needed.

  Printing is the one thing still refused over SMB2, and stays refused: the
  request it uses predates the print spooler interface and no current
  server implements it.

* Two faults in the SMB2 work, both found by testing it end to end rather
  than a feature at a time:

  The maximum transfer sizes were read from the wrong place in the
  negotiate response - they sit at offsets 28, 32 and 36, not 12, 16 and
  20, so what was being read was the middle of the server's identifier.
  The nonsense that produced was harmless until the buffer came to be
  sized from it, at which point a zero made the connection give up and
  fall back to SMB1 without saying so.  A connection that quietly uses a
  different protocol than the one asked for is worse than one that fails,
  so the fallback now applies only to a server that does not answer SMB2
  at all; anything that goes wrong after a dialect has been agreed is
  reported.

  SMB2 was using the core dialect's name mapping, which upper cases every
  name and cuts it to eight and three - correct for a 1987 server and
  quite wrong for this one, and it showed up as files arriving on the
  server in capitals.  It now takes the long-name mapping from the SMB1
  upgrade, which is the same job and already written.

* A read that is answered with less than was asked for is now treated as the
  end of the file rather than as an error, and the remainder of the caller's
  buffer is zeroed.  The old code assumed it always got everything it asked
  for and copied whatever happened to be left in the message buffer, which
  could be part of another file.

v2.08
~~~~~
* All files re-licensed under CDDL Open Source licence

* Username / password in front end UI character limit increased 

* When module registers with OmniClient, it now registers "omni_lm98"
  sprite rather than !lanman98 so that different art/thene can be used
  with Omni as compared with standalone front end.

v2.07
~~~~~
* RISC OS Developments Open Source release

* RISC OS 5 styled icons used on OS5
  Old icons included for OS4.x and earlier


v2.05/06
~~~~~~~~
* List of changes not available / unknown

v2.04
~~~~~
* Fix for unaligned access that stopped LanMan98 working with BeagleBoard.
  (Thanks to Alex Waugh for this, and most other v2.00+ work)

v2.03
~~~~~
* Allow IP address to be given after server name in {} in printer server field.

v2.01
~~~~~
* More timeout problems solved.

* Add a LanMan98$RawRead system variable to control whether raw reads are used
  or not (solves problems with badly behaved NAS).

v2.00
~~~~~
* Fix timeouts when connecting to Windows Vista.

* Work around several unsupported or buggy features in various NAS servers.

* Implemented support for LM and NTLM encrypted passwords.

* Improved handling of hidden files (They are still hidden from directory
  enumerations, but they can now be accessed directly by name).

* Changed default filetype to text.

* The frontend now remembers which mount link was loaded, and saves any
  changes back to it rather than creating a new link.

* Fixed a couple of bugs in the free space display.

* Improved some error messages.

v1.20
~~~~~
* Reorder name/name,### search for files that end in ~1 etc, so that I
  don't lose the file type.  Necessary because Windows allows access
  to both DOS and full names.

* Avoid NULL indirection in printer code.  Caused crashing when attempting
  to print to NT with insufficient access.

v1.19
~~~~~
* Ignore atributes outside of 0xFF, so to avoid files being copied from
  NetFS being given random combinations of the properties system, hidden
  and read only.

v1.18
~~~~~
* Connect window provided with option to save the password.

* Printer support avoids creating empty files when RiscOS tests the connection.

* GO back to using TCPIP v4 for support of old machines.

v1.17
~~~~~
* Stopped death of the server causing LanMan98 to crash.  It was a bad
interaction between the reconnection and keepalive mechanisms - now cured.
Also added code so that once a reconnection attempt fails, then all accesses
made in the next three seconds fail immediately.  This was needed because the
Filer asks for file details during redraws, and ignores error returns; hence
filer redraws could take timeout_period * No_of_files, if it wasn't for this
fix.

* Made hourglass appear while waiting for replies from the server.

* Made chockblock code work for all versions of RiscOS >= 0xA8.

v1.16
~~~~~
* Built with version of FSLIB that prevents the bug that causes copied
file to get the server's idea of now as their creation time.  Bug reappeared
because I didn't give him the FSLIB patch.

* 6-char extensions.

* NC excepts OS version above 106

v1.15
~~~~~
* Fixed "Broken pipe" when clicking bar icon problem.

* Made Filer icons the right size under RiscOS 3.1

* NC only version for Presedence.

* Fixed bug that made creating hidden files fall over.

v1.14
~~~~~
* Partial cure of "Broken pipe" problem.

* Altered parsing of printer file to allow for password with no user, and for
options.

* RiscOS 4 compatible version of CallBackPatch

* Mimetype support.

* notypes invokable from front end

* notypes shares closed on dismount

v1.13
~~~~~
* Made date and time swapping determined by tests on first file
  accessed. Microsoft can't even be consistent about getting it wrong.

v1.12
~~~~~
* Swapped order of date and time in TRANS2_QUERY_PATH_INFO; Oh thank you
  Microsoft!

* Try set-attr with last-write times for NT, and catch errors from W95, in
  which case go back to opening and closing the file.

* Linked with version of FSLIB that enables File 0 (Save) to get around
  date not being set with filer-action copies to NT.  Suspected RiscOS bug.

v1.11
~~~~~
* Allow user name and password to be specified within a printer specifier.

* Allow the password to be omitted from the command *LMLogon98

* Send username and password even if the server doesn't ask for it.  Samba
  needs this.

v1.10
~~~~~
* Reimplemented interface to Free module because the change to the FS word
  made in v1.08 causes OS_FSControl 49 to be disabled.

v1.09
~~~~~
* Cured problem with enumeration of empty root directories.

* Permit changing of default file type by setting system variable.

v1.08
~~~~~
* Reduced flush delay to 1cs, but allowed 100 failures before giving up.

* Retract claim in FS word that image support is required. This stops the
  problem with the system heap growing, for some unknown reason.

* Make directory enumeration conform to the defacto standard rather than
  the PRMs, so that Acorn's broken "Repeat" will work.

v1.07
~~~~~
* Implemented raw reads to improve speed.

* Made "notypes" mode show the full file names, including the ,XXX part.

* Fixed the problem with my last attempt at fixing the Fresco problem.

* Changed from using the system variable LanMan98$FrescoPatch to
  LanMan98$CallBackPatch.

* Made directory enumeration sensitive to the "end of search" flag, rather
  than waiting for a search that returns no entries.  Hope this gets around
  a problem with LanMan98 looping on a file called "<7f>".

* All system variables now prefixed by LanMan98 rather than just LanMan

* Reenstated flush delay for "non-specific" error.

v1.06
~~~~~
* Allowed for failure of NetBIOS name service socket, due to presence of
  LanManFS.  Also try broadcast of node status requests.  These two changes
  make locating of the PDC more likely during domain logon.

* Cut out some rubbish to make the module smaller.

* Made LanMan98 respect the hidden file attribute, unless the system variable
  LanMan$ShowHidden is set.

* Fixed Fresco problem.

v1.05
~~~~~
* Obtain file details via TRANS2_QUERY_PATH_INFORMATION (where possible) to
  allow access to files within non-readable directories.

* Removed flushing delay for the "Windows 95 is thinking about it" error.

* Stored last-used username and password for each connected server, for reuse
  as defaults.

* Made all disconnects close the associated filer windows with Filer_CloseDir.

* Ensured that ,XXX is recognised as a RiscOS type only when it is the end of
  the name.

* Use LanMan$NameServer and LanMan$Scope in place of commands.

* Improved NetBIOS name resolution.  First try broadcast; then try the name
  server (assuming LanMan$NameServer is set); then try gethostbyname.

* Implemented domain logon, with automatic mounting of the homedir-containing
  share, and setting of the LanMan$Homedir system variable.

* Fixed a bug in the code for protecting LanMan98 against reentrance.  Also
  made a version that handles reentrance (but it has strange interference with
  the WIMP).

* Make length-setting on printer files a null action, rather than throwing an
  exception.

v1.04
~~~~~
* Added HTML and JPEG to the mapping file.

* Corrected flaw in print streaming exception handling.  Caused !Printers to
  crash if connection failed.

* Decreased maximum size of read to fix SAMBA's tendency to drop the last byte
  in a maximally sized read.

v1.03
~~~~~
* Disconnect98 allows user name without password.

* Errors returned to ShowFree.

* Front end replacement for !Omniclient.

* Remote printing implemented.

v1.02
~~~~~
* Simple ARM coded version of longjmp and setjmp used in exception
  handling and threading.

v1.01
~~~~~
* Put CR in place of NL in help strings.

* Stoped SMB error numbers being returned to RiscOS.

* Error 0x01, 0x43 given message.

* "notypes" special field introduced.

* Filer_CloseDir on dismount.

* Corrected bug in file-opening, exception handling.

* Disconnect old connections on reuse of mount name.

* Check for multiple connections to shares.

* Force disconnect of all shares on module finalise.

* Use of Properly allocated SWI chunk and file system number.

v1.00
~~~~~
First complete version.
