                   Speak Freely Development Log
              by John Walker  --  kelvin@fourmilab.ch
                                        
23 August 1995

Initial announcement of Speak Freely Release 5.0.

24 August 1995

Peter Claus Gutman (pgut01@cs.auckland.az.nz), developer of a very
nice encryption library, wrote to suggest his library might prove
useful.  In the source code for the library, I found a clever 80x86
assembly-language implementation of IDEA, made freely available by its
author, who is identified in the source code only as "Bryan".  Whoever
you are, Bryan, great piece of work!  If you, or somebody who knows who
you are, happens to read this, let me know so I can give complete
attribution.
  
I integrated the assembly language loop into IDEA\IDEA.C, modifying it
slightly to work with Microsoft Visual C's inline assembler, so you
don't need a separate assembler to take advantage of the optimised
code.  Whether the assembler or original C code is used depends upon
whether USE_ASM is defined, so you can use the original loop for
reference or if, for example, your compiler doesn't support inline
assembly code or is incompatible with the way Microsoft do it.

Enabling the assembly language code increased the speed of IDEA encryption
and decryption on my 486/50 machine from 152,000 bytes per second to 242,000
bytes per second--well worth the trouble of integrating the code.
                                
30 August 1995

Completed a massive revision to avoid all packet fragmentation
and thus work with WINSOCK drivers such as Trumpet WINSOCK.  The
changes were so great and ubiquitous there's no point in trying
to describe them.  In debugging the changes, one of the mysteries
that has been dogging me was finally solved--the random hangs,
loss of synchronism, failure to release resources, etc. etc. etc.
were the result of Windows discarding messages to the main window
as a result of overflows of the default 8 message queue.  Speak Freely
juggles a lot of balls in the air at once, and it's very easy to
hit this limit.  At initialisation time, we now try to expand the
queue to its maximum size of 120 messages or whatever lower maximum
the system we're running on supports.

Added the "Extended Status" (Propeller Head) dialogue.

Made compression modes global rather than per-connection.  This
means compression only has to be done once, which speeds up
party line transmissions.  The change is necessary in any case
so that packet size can be optimised.

1 September 1995

Update release 5.1.

8 September 1995

CreateSocket() in UTILITY.C contained a "defensive bind()" to
address zero as a work-around for some defective WINSOCK implementations.
Unfortunately, this work-around causes other TCP/IP stacks, including
that built into Windows NT to fail.  I made the nugatory bind conditional
on a new Options/Workarounds/Always Bind Socket menu item which is, of
course, saved in the .INI file.

Update release 5.1a.

9 September 1995

Discovered that the reason the socket write was failing on Windows NT
and Windows 95 is that Microsoft's built-in WINSOCK, entirely
incompatible with Unix and every other WINSOCK I have encountered,
refuses sendto() once a datagram socket has been connect()ed.  The
sole function of connect() on a datagram socket is to specify a
default address so subsequent writes can be done with send() (or,
on Unix, write()), and there is no prohibition of overriding this
default address with a subsequent sendto().  The WINSOCK specification
nowhere mentions such a restriction as a Windows-specific change.  I
modified the socket write code in CONNECT.C and the loop-back socket
write in FRAME.C to first try sendto().  If it fails, send() is then
tried and if that works all subsequent socket writes for the rest of
the session are done using send().  This code has been verified to work
on both Windows NT and Windows 95 (first customer shipment edition).
Special thanks to John Deters (jad@DHDSC.MN.ORG) who both identified the
source of this problem on Windows NT and tested innumerable versions
slowly converging toward the actual fix.

Added an item to the Propeller Head dialogue to indicate whether sendto()
or send() is being used to write to outbound sockets; it's "Sending with"
in the "Network" box.

Tested with the WINSOCK implementation included with Sun PC-NFS 5.1.  Works
fine.

Update release 5.1b.

10 September 1995

After last week's experience I decided to indulge in some preemptive
workarounds for crummy network and sound card drivers which fail in
obvious ways which haven't bitten me yet.  I expanded the Options/Workarounds
menu to include:

    Audio
        Assume Half-duplex
            Assumes the sound card is half-duplex without requiring it
            to fail an output open while input is open.  Accommodates
            cards which are actually half-duplex but don't indicate this
            by failing a simultaneous input and output open.  Also handles
            cards which crash the system or application when you try to
            open them in full-duplex mode.
            
        Assume 11025 Samples/sec
            Assumes the card is capable only of 11025 samples per second
            mode, not our preferred 8000 samples per second.  Permits
            correct operation on cards which don't fail when opened with
            a sample rate of 8000 samples per second but which can't
            actually run at that rate.
        
    Network
        Always Bind Socket
            As before; bind outbound sockets, even though there's no need
            to do so.
            
        Never Connect Outbound Socket
            Don't connect() the output sockets.  This implies we'll always
            use sendto() to write to those sockets.  Clears "Use send(), Not
            sendto()" mode if set.
            
        Use send(), Not sendto()
            Always use send() to write to outbound sockets; don't wait for
            a sendto() to fail first.  Accommodates drivers where a sendto()
            on a connected socket crashes the application or system.  Clears
            "Never Connect Outbound Socket" mode if set.
            
All the workaround modes are saved in the SPEAKFRE.INI file and apply to
subsequent executions.  The menu items are disabled when a connection is
active. 

As suggested by John Deters (jad@DHDSC.MN.ORG), I added the ability to
automatically open an iconised version of Speak Freely whenever a new
inbound connection is established.  This lets you see the site that's
just started talking to you.  Since some people might find such an
unsolicited pop-up irritating, this only happens if you check the new
Options menu item "Look Who's Talking".

Tested under Windows 95 final build.  Works fine when using the standard
built-in WINSOCK, but doesn't resolve host names when Sun PC-NFS is
overloaded on top of Windows networking.  This appears to be a general
problem of this configuration; other programs fail on gethostbyname()
in precisely the same way.  When you configure Windows 95, be sure to
install the TCP/IP driver; if you don't you'll get nowhere fast.

12 September 1995
       
Sending a stereo .WAV file in ADPCM compression mode crashed the Unix
speaker program.  The code in READWAVE.C which calculates the number of
bytes of .WAV file needed to fill a packet was incorrectly assuming the
nBlockAlign field was the size of an individual sample, not the frame
of samples for all channels.  Fixed.

Closing a connection while a .WAV file was being sent orphaned the MMIO
handle used to read the file.  Fixed in CONNECT.C.

13 September 1995

Added the ability to drop saved connection (.SFX) files in the MDI frame
window and thereby open (or activate, if already open) connections to
the hosts given in the files.  You can drop multiple connection files in
a multiple selection and each will be opened.

CONNECT.C had its own implementation of DragAcceptFiles() which directly
twiddled WS_EX_ACCEPTFILES.  It doesn't any more.

If a connection file is named on the command line when the program is
launched, it is opened once the application is initialised.  This
permits making an association between the .SFX extension and Speak
Freely in the File Manager and launching the program for a given
connection by double clicking the connection file.  You can specify
multiple connection files on the command line, space separated.  This
allows making a program item icon which opens a collection of
connections, a handy thing to put in your StartUp folder.  (Suggested
by John Gilmore (gnu@toad.com)).

John also pointed out that the program wasn't usable without a mouse
since the left mouse button was the only way to push to talk.  I added
logic in CONNECT.C that permits the space bar to be used to toggle
push to talk, just as in the Unix mike program.  You can cycle between
open connections with Ctrl+Tab and use the space bar to select any set
to which you wish to transmit.

Mouseless users who push to talk with the space bar don't have the
benefit of the cursor change to indicate which connections are
transmitting.  I added a "Transmitting" status indicator in the
connection window which appears whenever live audio is being sent to
the window.

If you make a .WAV sound file with the (nonstandard) sampling rate of
8000 samples per second, it is now played correctly by READWAVE.C, not
forced to the closest standard sampling rate of 11025 samples per
second.  Conversion of stereo .WAV files into mono is still performed
for 8000 sample per second files.  If the user has the ability to make
8000 sample/sec .WAVs, this reduces file size, improves sound quality,
and eliminates CPU overhead when sending such files.  .AU files remain
the fastest, since they're already mu-law encoded.

14 September 1995

Update release 5.1c.

20 September 1995

Began work on answering machine.  Defined structure for data in file,
added a new ANSWER.C module with a function to save a sound buffer
in an answer file in that format.

25 September 1995

Modified the new connection dialogue handler to allow numeric IP
addresses which can't be resolved into host names.  If the host
name lookup fails, the dotted IP number from inet_ntoa is used as
the host name.

Good ole' Trumpet Winsock returns an error status if gethostname()
is called with a buffer too small to hold the entire name, as opposed
to truncating it as Unix does.  I changed the two calls in CONNECT.C
to get the host name in a temporary buffer, then copy as much as will
fit into the sendinghost field of the sound buffer.

Added the ability to set the multicast scope with a new item in the
Options/Connection dialogue.  This item is enabled only if the IP
address is a valid multicast group number. 

Bad ole' Windows 95 WINSOCK returns a WSAEFAULT error if you pass a
single byte argument for the IP_MULTICAST_TTL setsockopt() call.  This
is incompatible with all Unix documentation I have seen.  Trumpet
works correctly with the single byte argument, and accepts the 2
byte short required by Windows 95.  Given the likelihood there's some
other WINSOCK that requires a one byte argument, in goes another
Options/Workaround/Network item: "Multicast TTL Argument Is char" which
does it the Unix way, not as required by Windows 95.

26 September 1995

Added a new Connection/Multicast Groups... dialogue which allows
adding and dropping membership in multicast groups.  Groups can be
specified by DNS-resolvable name or by IP address.  A check box
controls multicast loop-back of locally sent packets to groups
in which this host has added membership.  The loopback box is disabled
on systems (such as Windows 95) which do not implement the IP_MULTICAST_LOOP
setsockopt() option.

1 October 1995

Discovered the multicast tear-down code in the WM_DESTROY message handler
of FRAME.C wasn't testing for a NULL multiName[], resulting in bad
GlobalFree() calls when we failed to initialise a multicast port.  Fixed.

FRAME.C wasn't killing the main timeout timer at WM_DESTROY.  Fixed.

If the attempt to drop a multicast membership at WM_DESTROY time failed,
a message box was displayed as a child window of the one frame being
destroyed.  This is apparently (yet another of the billions and
billgatesillions) undocumented no-no--in any case, if you do it, you
get an "err USER: Attempt to activate destroyed window" at the
time the WM_DESTROY returns.  I changed the parent of the message box
in this case to be NULL and it seems to be happy now.  (In FRAME.C).

Finished implementation of the answering machine, ANSWER.C.  I'll probably
be back before long to make it more message-oriented (select message from
a list box of sites and times, individually delete messages, etc.) but at
least it now has basic functionality.

2 October 1995

Added keyboard accelerator (CTRL+T) for answering machine, and a new
connection menu item that lets you toggle whether incoming messages are
recorded without having to pop up the answering machine dialogue.  Fixed
a bug in which checking or unchecking the record incoming messages box
in the answering machine dialogue didn't take effect until you closed
the dialogue; now it takes effect immediately.

Added code to overwrite the 16 byte session key exchanged via PGP before
closing the file on disc.  Unfortunately, since we can't transmit and
receive the with a pipe, as we do on Unix, there's still a window while
PGP is running during which the session key is visible, but at least this
keeps it from lying around in unallocated disc space for an indeterminate
time.

If no answering machine message file was configured, the answering machine
dialogue in ANSWER.C called scanMessageFile anyway.  Unfortunately, that
routine didn't test for answerFile being NULL and proceeded to stomp all
over memory.  Fixed in ANSWER.C scanMessageFile().

Moved all translatable strings and formats from the .C modules into the
string table of the resource file, using the rstring(), rfilter() functions
and the Format() macro as intermediaries.  Strings that aren't to be translated,
such as fopen() mode strings, formats that contain only a field editing
code, etc. continue to appear as strings in the source code.  Banishing these
strings to the resource file reclaimed almost 4K of data space, enough to give
us some breathing room should it prove necessary to introduce another static
full-size sound buffer for some reason.

3 October 1995

The enabling and disabling of buttons in the answering machine was befuddling
Windows' dialogue box keyboard accelerator logic.  I added code at the end of
a message replay to restore the input focus to the button last pressed or
its logical successor if that button has become disabled as a result of the
message we just completed.

Keyboard accelerators in the answering machine were less than optimally
chosen due to renaming of buttons during its development.  I rationalised
them so the most commonly used buttons have the most obvious keyboard
shortcuts.

Pressing the Close button in the answering machine gave a debug kernel
"err: window destroyed in window callback".  Why, I know not.  It uses
the standard code for modeless dialogues right out of Petzold, which
identical code works perfectly in the propeller-head modeless dialogue.
Changing the DestroyWindow() to a PostMessage of WM_CLOSE to ourself
made the message go away.  I changed the propeller-head dialogue in
DIALOGS.C to use the same logic.

Several modal dialogues needlessly included the system menu in their title
bar.  Eliminated.  (The modal dialogues such as the answering machine and
propeller-head continue to display the system menu.)

Installed help buttons in all the dialogues, linked to the topic
in the help file which describes the dialogue.

Moved the names of our help file and the base Windows help file into
the resource string table.

The Create Key menu item was missing the "..." that indicates it pops
up a dialogue.  Fixed.

The About dialogue was also missing the "...".  Fixed.

I removed the "How to use help" menu item, which has fallen out
of fashion.

Changed "Help/Search..." to "Help/Search for Help on..." as used in current
Microsoft applications.

4 October 1995

Completed moving all section and item titles for the main .INI file and
saved connection files to the string table in the resource file.  Whether
these should be translated isn't clear: a normal user won't ever examine
these files and translating renders them incompatible between different
language editions.  But the saving in data segment size by elminiating
duplication of the section titles alone justifies the work.

Added two new string constants kS0[1] = "0" and kS1 = "1" to FRAME.C and
changed all references to the explicit constants in profile file I/O to
use them.  This eliminates redundant string constants in the data space.

Found a few string constants I'd missed somehow in READWAVE.C.  Banished.

Fixed the answering machine to update the host name when
a definitive name (one not displayed in parentheses) is seen, replacing
any previously displayed name.

Added help butttons to all the file open dialogues, linked to the
appropriate topics in the help file.

Added a pleasant default ring file.  I haven't found a suitable (well-recorded
and public domain) telephone bell, so I decided to pioneer non-irritating
notification of an incoming call with this wind chime derived sound.  The
original appeared on the CD-ROM (N 5) accompanying "News Windows" N 26
(octobre 1995) as the file WINDBELL.WAV.  I used Silicon Graphics' soundfiler
to convert this from an 11025 kHz PCM stereo file to an 8 kHz monaural
.AU file for optimal transmission.

Substantial data space was being wasted by repeated constant references to the
profile (.INI) file name.  I moved this string to the string table in the
resource file and changed the code that loads and saves the global configuration
to load it once into a string on the stack and reference that temporary copy
in all the [Read|Write]PrivateProfile... calls that follow.
 
Added a new MAKEBIN.BAT file in the home directory which builds the binary
release archive.  Now that the release includes more than the .EXE and .HLP
file, something more archival than my fallible memory is needed to make sure

5 October 1995

Remade all screen shots for help file, the addition of the help buttons
required updating all the dialogue bitmaps.

Added logic to the invocations of PGP in FRAME.C and DIALOGS.C to
first try to use the SFPGP.PIF file from the Speak Freely release
directory (obtained with GetModuleFileName) and then, if that fails,
fall back to call on PGP counting on path search to find it.  Going
through the PIF allows the user to override the default modes for
a WinExec call to a DOS program such as PGP, in particular, to run it
in a window, which is much less disruptive of the user's equanimity
than blasting out to a DOS prompt.

6 October 1995

Feature release 5.3.
