HISTORY.TXT (for DosLynx v0.32b, July 2006) by Fred C. Macall Introduction This is for my eleventh release of DosLynx. In this document, I'll try to take up where I left off in the last history.txt and not rehash the history of the previous versions. However, there is a cumulative list of unresolved bugs, issues, and To Do(s) at the end. If you want to know everything else there is to know about my previous releases of DosLynx, you can get most of that history from: http://users.ohiohills.com/fmacall/dlx2xdoc.zip . This archive collects the info.htm and history.txt documents for all eight of my DosLynx v0.2xb releases. For the rest, the documents for DosLynx v0.30b and v0.31b are available at: http://users.ohiohills.com/fmacall/dlx30/info.htm http://users.ohiohills.com/fmacall/dlx30/history.txt http://users.ohiohills.com/fmacall/dlx31/info.htm and http://users.ohiohills.com/fmacall/dlx31/history.txt . In February, I was able to add a Windows 2000 Pro, SP3, installation to my Pentium based home networked PC, Digerydo. Digerydo runs at 60 Bogo MIPS and has 64 MB of RAM. This new installation has provided my first Windows 2000 DOS window experience with DosLynx. In the last history.txt, I was "pleased to note that no unpleasant surprise came from DosLynx, in this new experience." Well, only a big oversight in my early tests with Windows 2000 allowed me to say that. I failed to notice a DosLynx Protected Mode version problem with the stock Windows 2000 mouse driver. DosLynxP crashes, with a registers snap, as soon as the mouse moves for the first time in a session! I haven't been able to fix this problem, yet. However, I have provided a bypass, in the form of a new mouse= configuration item. It provides for ignoring the mouse in a troublesome installation. It is described below, under the heading: mouse= Configuration. In April, my development PC, Sailboard, came down with keyboard trouble, again. For the second time in only a little more than six months. Last fall, I found a deteriorated plated wiring keyboard lead causing the problem. It was one running under the CMOS battery. Perhaps battery juice precipitated corrosion was behind that failure? This time, the problem might be the same kind of failure in another keyboard lead. However, this time, the failure came shortly after I had decided to release DosLynx v0.31b. And, I realized how risky it is to be working on a motherboard problem, on a system with a disk full of un-backed-up development files! So, I decided to transfer Sailboard's disks to a '97 IBM Aptiva PC. This is a Cyrix 6x86 based system, with 16 MB of RAM, that runs at about 132 Bogo MIPS. That eight times speed increase, from Sailboard's 16 Bogo MIPS, has reduced the time for making DosLynx by almost a third. And, having spent some time configuring the Aptiva, I'm finding it hard to get around to trying to repair Sailboard, again. My excuse is that my regular testing with Zeke still keeps me in touch with the feel of DosLynx on an old (read: slow) PC. Old Business I've found and fixed three more kinds of lapses in the bottom line Command Status Indicators' initialization and updating. First of all, they weren't being initialized correctly, to off. That was apparent when the /HOFF command line option, or an equivalent, was used to keep DosLynx from displaying an initial document. I've fixed that by adding TView::disableCommand( ) calls, one for each of the five Command Status Indicators, to the end of TCapture::TCapture( ), in TCAPTUR2.CPP. When a window was left containing only a single document, the bottom line Prior Command Status Indicator might have been left on, erroneously. The Navigate|Reload Current menu entry or command readily demonstrated this issue. This trouble came from adding a new visitlog entry to the window's history Collection while doing a Reload. The old visitlog entry got removed at the end of the operation. But, the Prior Command Status Indicator was left reflecting the extra entry seen during its update. To fix this kind of problem, I've added TURLWindow::setComs(1) calls in several places. 'setComs( ) was introduced in the history.txt for DosLynx v0.29b. I've added 'setComs(1) calls to the end of cases cmCascade, cmReload, and cmLoadParent, in TURLWindow::handleEvent( ) in TURLWIN4.CPP. I've added a 'setComs(1) call to the end of TURLWindow::dragView( ), in TURLWIN5.CPP. And, I've added a 'setComs(1) call to the end of TURLWindow::TURLWindow( ), in TURLWIN8.CPP. These added 'setComs(1) calls run after any temporary extra visitlog entry has been destroyed. Where there can be no mistake about the Prior Command Status Indicator's setting. I also noticed that the Activate Command Status Indicator might get left with an incorrect indication after a rapid series of Tabbing and/or scrolling operations were performed, on a slow machine. This was seen to be due to an inability, in TURLView::draw( ) in TURLVIE6.CPP, to signal every TAp_selected change, on a slow machine. To fix this, I've extended 'draw( ) to clear its TApselcp variable when it finds a TAp_selected change while itapschd is set. HTAnchor * TApselcp is the global that 'draw( ) uses for remembering TAp_selected, in order to detect TAp_selected change(s). itapschd signals that a Command Status Indicators update is needed, to reflect a TAp_selected change. It was introduced in the history.txt for DosLynx v0.30b. Once it has cleared TApselcp, 'draw( ) now continues to find TAp_selected apparently changed. Until itapschd finally goes clear, indicating that a Command Status Indicators update has been accomplished. At that point, 'draw( ) signals an additional TAp_selected change. With the result that the Command Status Indicators get reupdated and brought up-to-date. The DosLynx Protected Mode version hasn't been removing its temporary files upon exit. The provision for removing abandoned temporary files at the beginning of each DosLynx run has kept this lapse from causing a troublesome accumulation of temporary files. However, this hasn't been what I intended. For whatever reason, the TDL.~TDosLynx( ) call needed to destroy the Protected Mode version's TDosLynx object wasn't getting made during shutdown. That call leads to removing a DosLynx run's temporary files. To fix this issue, I've added an explicit TDL.~TDosLynx( ) call to the end of the DosLynx Protected Mode version's main( ), in MAIN.CPP. domainslist= Configuration domainslist= has been called a "Mandatory [configuration] option", in DOSLYNX.CFG. This was technically correct. Because, the char * def_domain variable that points to the domainslist= configuration value wasn't being initialized any other way. However, it wasn't very helpful to be trying to force domainslist= configuration in this way. This situation was aggravated by my providing domainslist="mydomain.com" in the sample DOSLYNX.CFG file. Because, as it turns out, there is a Domain Name Server for mydomain.com. And, it doesn't seem to mind sending one of its domain's IP address(es) in response to all requests that look anything like: anything.mydomain.com . As a result, a new user who let domainslist="mydomain.com" stand, in his DOSLYNX.CFG file, got the same or a similar document presented for almost every URL requested! I've added = 0 to the declaration of def_domain, in UDP_DOM.C. So, domainslist= won't have to be a mandatory configuration option anymore. Of course, I've also updated the comments for domainslist= , in DOSLYNX.CFG. In particular, I've revised and commented-out the sample value. Now it reads: ###domainslist="mysitesdomain.com" mouse= Configuration As explained in the Introduction, the DosLynx Protected Mode version has run into a fatal problem with the stock Microsoft mouse driver provided to a Windows 2000, SP3, DOS window. Eventually, DosLynx may be able to bypass that problem by always treating the mouse driver as a Real Mode process. (It is already doing this for the Packet Driver.) However, that remains to be seen. Since DosLynx does nothing that can't be expressed via the keyboard, another bypass for this issue is to ignore a troublesome mouse driver. I've added mouse= configuration for this purpose. To make the mouse driver ignorable, I've added public: static int enaMouse to the definition of class THWMouse, in Turbo Vision's SYSTEM.H. An int THWMouse::enaMouse = 0 declaration, added to Turbo Vision's TMOUSE.CPP, instanciates this new variable. I've extended THWMouse::resume( ), in TMOUSE.CPP, to check enaMouse along with the Real Mode INT 033h Vector. Finding either of these zero, 'resume( ) immediately returns. With the result that no further mouse driver access or usage is attempted. Unless or until 'resume( ) gets rerun with a non-zero value in 'enaMouse. As 'resume( ) first gets run as part of the Turbo Vision package's construction, the mouse driver will get ignored very early in the construction of DosLynx. Before the DosLynx configuration has been read from DOSLYNX.CFG. So, it is up to the DosLynx initialization and configuration process to update 'enaMouse and get 'resume( ) rerun, if the mouse driver isn't to be ignored. After making these changes, a new make of Turbo Vision was required, of course. Conversely, a THWMouse::enaMouse = 8 statement added early in TDosLynx::EvalConfigFile( ), in TDOSLY14.CPP, provides the default mouse driver enabling seen by the user. It is up to later mouse= configuration handling code in 'EvalConfigFile( ) to clear enaMouse back to zero, if the mouse driver is to remain ignored. The latter code uses #ifdef __DPMI16__ conditioned logic to provide possibly separate mouse= configuration for the DosLynx Real Mode and Protected Mode versions. See the updated DOSLYNX.CFG file for more details on the simple configuration options provided. Finally, a TEventQueue::resume( ) call added to main( ), in MAIN.CPP, leads to a rerun of THWMouse::resume( ). This call comes just before main( ) calls TDL.run( ), which performs the DosLynx idle loop. If 'EvalConfigFile( ) has left 'enaMouse non-zero, the rerun will get any mouse driver installed in the Real Mode INT 033h Vector activated, after all. HTTP Header Referer: Field Support A few HTTP servers won't honor requests that don't include satisfactory Referer: field content. As it hasn't been providing this field in its requests, DosLynx hasn't been able to work satisfactorily with those servers. This lack has now been remedied, as follows: As explained in RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1, section 14.36, the Referer: field is expected to report the URL of the document containing the link being requested. (That specification also acknowledges that its Referer keyword is a misspelling of the word referrer.) The Referer: field punches a hole in your security, then, by confirming or revealing what it is that you are reading. To give you a lot of control over use of the Referer: field, I've implemented it together with a two level control arrangement. Both levels have a veto over sending the Referer: field. A new refmode= configuration item provides the first level of control. DOSLYNX.CFG provides a new section describing this configuration. A new Options|Manage HTTP Referer Mode menu entry or command provides the second level of control, or management. By default, sending the Referer: field remains disabled or vetoed. extern int refmode and extern char * cp_referer, added to GLOBALS.H, provide much of the data for this new feature. I've also added a definition for const unsigned short int cmRefMode, to GLOBALS.H. This code stands for the command that implements the new Options|Manage HTTP Referer Mode menu entry. refmode and cp_referer are instanciated, with initial values of zero, in GLOBALS.CPP. Bits of refmode remember the HTTP Referer mode's configuration and ON/OFF status. cp_referer conveys a copy of a Referer URL string, or zero, from all the places where HTTP requests originate, to HTLoadHTTP( ), in HTTP.C. cp_referer is zeroed for requests that come from the File|Open URL... and File|Open Local... menu entries or commands and from DOSLYNX.CFG. Because, those sources don't have recognized URLs. If no document ever had to be reloaded from its original source, refmode and cp_referer would be all the data needed for this feature. But, obviously, documents do have to be reloaded. Sometimes, long after they were first loaded. How will we provide for the Referer: field when requesting a document reload? My answer is to add a char * ref variable to the struct visitlog object that was introduced in the history.txt for DosLynx v0.20b. It is a Collection of struct visitlog objects that remember each DosLynx window's history. The definition of struct visitlog is included in TURLVIEW.H. ref takes over any cp_referer string in existence at the time of each visitlog object's construction. Finding refmode= configured, TDosLynx::EvalConfigFile( ) in TDOSLY14.CPP, may set Enable and Audit or OnOff bit(s) in refmode. Once 'EvalConfigFile( ) has been run, only refmode's OnOff bit is subject to any further change(s). And, then, only if the refmode= configuration has specified one of the enable options. TDosLynx::initMenuBar( ), in TDOSLYN9.CPP, has been extended to provide an Options|Manage HTTP Referer Mode menu entry. This entry leads to the new cmRefMode command, implemented by new case cmRefMode in TDosLynx::handleEvent( ) in TDOSLYN7.CPP. This command provides a dialog reporting the status of all three of refmode's operative bits. When refmode's Enable bit has been set (by refmode= configuration), this dialog also provides a push button for toggling refmode's OnOff bit. This dialog's other push buttons simply provide various ways for dismissing the dialog without changing anything. Most of the rest of the new arrangements are involved in establishing values for cp_referer. First of all, TDosLynx::OpenLocal( ), in TDOSLYN4.CPP, always clears cp_referer. Because, none of its callers can have a referrer. TDosLynx::OpenURL( ), in TDOSLYN3.CPP, clears cp_referer, when called without a parameter, for the same reason. (When called with a parameter, its caller should have set cp_referer appropriately.) main( ), in MAIN.CPP, clears cp_referer before calling TDL.OpenURL( ) with the Home Page URL as a parameter. TDosLynx::handleEvent( )'s case cmHomePage does this, as well, before calling 'OpenURL( ). TDosLynx::EvalOption( ), in TDOSLY12.CPP, clears cp_referer before calling TURLWindow::TURLWindow( ) to construct a new TURLWindow. There is a lot of code involved in performing document reloads of various kinds. As a result, I have wound up with two new functions for setting cp_referer, by copying the ref entry from a struct visitlog object. TURLWindow::rlrefer( ), in new module TURLWI15.CPP, uses TNSCp_visited->getCount( ) and TNSCp_visited->at( ) calls to locate the most recent struct visitlog object in a window's history. TURLWindow::rvrefer( ), added to TURLWIN4.CPP, takes a const visitlog * parameter for identifying a struct visitlog object to be used. These functions have been added to the definition of class TURLWindow, in TURLWIND.H, of course. Once they have a struct visitlog object in hand, 'rlrefer( ) and 'rvrefer( ) both perform the same process. Perhaps, I'll consolidate them into a single function one day. They copy the struct visitlog's ref value into cp_referer. If the result of this is zero, they copy the struct visitlog's url value into cp_referer. In other words, when reloading a document (which is, therefore, knon to exist), we may use the document's own URL as a reference. If/when the document was first obtained without reference to a referrer. This seems to make sense -- even for documents that don't contain self-referential link(s). TURLWindow::handleEvent( ), in TURLWIN4.CPP, may call 'rlrefer( ) to set cp_referer, from its cases cmCascade, cmReload, and cmDownLoadThis. TURLWindow::dragView( ), in TURLWIN5.CPP, and TURLWindow::IndexQuery( ), in TURLWI10.CPP, also call 'rlrefer( ). TURLWindow::handleEvent( ) may call 'rvrefer( ) from its cases cmLoadParent and cmNavGo. TURLWindow::TURLWindow( ), in TURLWIN8.CPP, uses 'rvrefer( ), too. TURLWindow::handleEvent( ), may set cp_referer in its case cmLoadChild, ahead of its call to either 'URLoader( ) or TURLWindow::TURLWindow( ). This is the case to be expected from a top level view of the Referer: field. TURLWindow::URLoader( ), in TURLWIND.CPP, copies cp_referer into the ref value in the struct visitlog object that it constructs for a new window. TURLWindow::TURLWindow( ), in TURLWIN8.CPP, does this too. And, TURLWindow::handleEvent( )'s case cmAddToHist copies a ref value from an existing struct visitlog object to a new struct visitlog object. As a precaution and to conserve memory, 'URLoader( ) clears cp_referer after every successful or unsuccessful document load operation. The work listed above, for setting cp_referer and struct visitlog object ref values, gets done whatever refmode contains. This insures that any needed ref value(s) will be ready whenever the refmode OnOff bit is or gets set. We're also saving on the code that would be needed for checking refmode's status in those processes. Finally, HTLoadHTTP( ) performs what is the object of all this effort. Finding refmode's OnOff bit set and cp_referer non-zero, it adds a Referer: field to the Request that it assembles. If refmode's Audit bit is also set, it reports the same Referer: field information to the Messages window. Video Mode Fixes If you've never started DosLynx in a video mode providing more than 25 lines. And, if you've never tried to switch DosLynx to "HIGH" video mode while using a Hercules or other monochrome display. Then, you probably thought DosLynx had adequate video arrangements. But, if you had tried the first, you might have gotten some strange results. And, if you ever tried the second, you might have gotten an apparent crash! I think these were the worst video problems DosLynx had. I've also found and fixed a few less severe video issues. The first problem identified above came from DosLynx declaring, to itself, that it would perform its initialization for a 25 line video mode. While doing nothing to assure that a 25 line video mode was actually in effect. TDosLynx::TDosLynx( ), in TDOSLYNX.CPP, made this declaration. Less comments, it read: B_isLow = True ; I've changed this empty declaration to the following short sequence for insuring that a 25 line video mode is actually in effect: B_isLow = (Boolean) ((TScreen::screenMode & TDisplay::smFont8x8) == 0) ; if (!B_isLow) switchVideo( ) ; This works by checking Turbo Vision's information about the present video mode. That is contained in TScreen::screenMode. TDisplay::smFont8x8 is a mask for the bit used to indicate a high (43 or 50 line) video mode. 'switchVideo( ) is TDosLynx::switchVideo( ), in TDOSLY16.CPP, which is discussed further below. If you now start DosLynx in a high (43 or 50 line) video mode, it consistently will make a switch down to 25 line mode. Before performing the rest of its initialization. You can, of course, choose the HIGH video mode, in your DOSLYNX.CFG file. Or, on the DosLynx command line. Or, via the Options|Toggle Low/High Text Mode menu entry or command. In those cases, DosLynx will be making an additional switch. Back to your requested high video mode. As for the apparent crash identified at the beginning of this section: That was attributable to TDosLynx::switchVideo( ), introduced just above. This is pretty involved. But, we'll give it a try. To do its work, 'switchVideo( ) calls TProgram::setScreenMode( ), in Turbo Vision module TPROGRAM.CPP. To do its work, 'setScreenMode( ) calls TScreen::setVideoMode( ), in Turbo Vision module TSCREEN.CPP. 'setVideoMode( ) does its work by calling TScreen::fixCrtMode( ), TDisplay::setCrtMode( ), and TScreen::setCrtData( ). These are all in TSCREEN.CPP, as well. 'fixCrtMode( ) is a key player in this. In effect, it limits or forces the given video mode parameter into one of only five possible values. These are: TDisplay::smMono (BIOS video mode 0x07), in 25 line mode, only. TDisplay::smBW80 (BIOS video mode 0x02), in 25 line or high (43 or 50 line) modes. And, TDisplay::smCO80 (BIOS video mode 0x03), in 25 line or high (43 or 50 line) modes. These five video modes are the only ones that Turbo Vision fully supports. TDosLynx::switchVideo( )'s call, for setting the HIGH video mode, used to read: setScreenMode(TDisplay::smFont8x8) ; Since that call's TDisplay::smFont8x8 argument lacked a base video mode value, it didn't match any of the five values that 'fixCrtMode( ) requires. That resulted in 'fixCrtMode( ) forcing 'smCO80 mode, along with the TDisplay::smFont8x8 bit for a 43 or 50 line mode. Apparently, trying to apply that mode, with a Hercules video BIOS, led to the resulting apparent crash. Turbo Vision intends to avoid loosing control of the display by limiting the use of 'smMono mode to only 25 line mode. To fix this issue, I've changed that troublesome call to read: setScreenMode(TScreen::startupMode | TDisplay::smFont8x8) ; Turbo Vision will have noted the video mode it found when it started, in 'startupMode. And, guess what? With a Hercules video card, that startup video mode will be found to be 'smMono. 'fixCrtMode( ) will remove the TDisplay::smFont8x8 part of the argument or parameter and return. With the result that the system remains in 25 line mode and avoids the apparent crash. A couple other changes were needed, in 'switchVideo( ), to complete this fix. First, since the switch from 25 line mode to high (43 or 50 line) mode may not actually occur now (as explained just above), B_isLow needs to be updated accordingly. Rather than simply toggled. I've substituted another copy of the TScreen::screenMode based expression, given at the beginning of this section, for updating B_isLow in 'switchVideo( ). Next, TDosLynx::switchVideo( )'s switch from high (43 or 50 line) mode to 25 line mode had to be dealt with. It used to read: setScreenMode(TDisplay::smCO80) ; By forcing 'smCO80 mode, that might have made trouble for a system running in 'smBW80 mode. I've changed that call to read: setScreenMode(TScreen::startupMode & (~TDisplay::smFont8x8)) ; If (TScreen::startupMode & (~TDisplay::smFont8x8)) doesn't evaluate to one of the three base modes that 'fixCrtMode( ) tolerates, it will (still) force 'smCO80 mode. So, this was a fairly modest change. Finally, as was the case with Zooming, the Messages window could be left scrolled to other than its customary end-of-list position after a video mode change. I have previously discussed this kind of issue under the heading: Zooming the Messages Window, in the history.txt for DosLynx v0.26b. I don't want 'switchVideo( ) to be forcing the Messages window open. So, I don't think this issue can be completely resolved in 'switchVideo( ). However, I did accomplish part of the fix by adding the following magic incantation to the end of 'setVideo( ): if (TC && TC->exposed( ) && TC->TT) TC->TT->do_sputn("", 0) ; To do that, I had to change TTerminal * TT from private to public in the definition of class TCapture, in TCAPTURE.H. (Hint: TCapture * TC is global defined in GLOBALS.H and GLOBALS.CPP.) I also felt it necessary to extend TCapture::TCapture( ), in TCAPTUR2.CPP, some, to insure that TC->TT is always defined, when TC is non-zero. Where TT wasn't defined before, 'TCapture( ) now leaves it zeroed. The rest of this fix comes in case cmUnHideMessage, in TDosLynx::handleEvent( ) in TDOSLYN7.CPP. This may be seen as follows: If TC->exposed( ) isn't True when 'setVideo( ) runs, the Messages window won't be seen until it gets unhidden. The messages window may get unhidden when a message gets added to it and when case cmUnHideMessage runs. Adding a message takes care of the present issue. So, only case cmUnHideMessage needed further attention. As case cmUnHideMessage already had testing that establishes the existence of TC and TC->TT, it was only necessary to add the following call, there: ::TC->TT->do_sputn("", 0) ; I have now come full circle on this business. I realized that the magic incantation I had been so pleased to add to the end of TCapture::handleEvent( ), in TCAPTUR3.CPP, may have been a little abrupt. I've extended it to read: if (zooming && TT) TT->do_sputn("", 0) ; Do you notice how it takes more and more code to accomplish less and less, when one gets real particular? Or, when one tries to go across the original design's "grain"? A remaining video problem comes from the use of VESA video mode(s) while starting DosLynx. Turbo Vision's arrangement(s) for saving and restoring its startup video mode may break down for some VESA video mode(s). Protected Mode Version's (Un)Reliability After the release of DosLynx v0.31b, the DosLynx Protected Mode version should have been just as reliable as the Real Mode version. But, it wasn't. I found the Protected Mode version to be unreliable in receiving long video files from the Internet. Files with lengths in the range of 20 MB to 80 MB. The DosLynx Protected Mode version would frequently hang while receiving such files. After a reBoot, there might be little or no sign, on the disk, of the data that should have been received during the time that DosLynx seemed to have been running! The DosLynx Real Mode version received the same kind of files quite reliably, on the same system. What could the matter be? The only clue I had, to start with, was an occasional Protected Mode violation in FRAGMENT.C. These were reported near the end of the lengthy Old Business section of the last history.txt. The frequency of these Protected Mode violations was much less than the frequency of undiagnosed hangs. My main theories were that I might be running into some kind of Stack overflow. And/Or, that the DPMI environment was being too slow in delivering the Packet Driver's interrupts, into Real Mode. Around the middle of June, I finally made a breakthrough in my thinking. I realized that I ought to do some testing on my LAN, for this issue. I started trying to receive a 262 MB file from HTTP and FTP servers on Digerydo's Windows 98 SE system. And, quickly ran into the then familiar hangs, with the DosLynx Protected Mode version! Being able to test for a problem this way, makes it much more practical to do experiments expected to be fairly unlikely to produce new information about the problem. At about the same time, I had been thinking about providing a Stack area for the use of cDPMIsri( )'s target(s). cDPMIsri( ) was introduced under the heading: Protected Mode Packet Driver Interface, in the history.txt for DosLynx v0.30b. cDPMIsri( ) had been relying on the DPMI provided Stack, which is said to be quite small, for its target(s). I would lengten the DOS memory buffer used for conveying transmit packets to the Packet Driver, to include a Stack area. Doing this involved relatively small changes in DPMIRUN.CPP and the Protected Mode version of TDOSLYNX.CPP. While working on the Stack area for cDPMIsri( )'s target(s), I also noticed a serious error in the setup for a similar Stack established by swapcall( ), in the Protected Mode version of TDOSLYN7.CPP. swapcall( ) was introduced under the heading: Protected Mode Swap Out, in the history.txt for DosLynx v0.30b. After implementing the new Stack and correcting the existing Stack, I did some testing on my LAN. And, fairly quickly found that the Protected Mode version's unreliability wasn't cured, yet! The new Stack helps me sleep better at night, however. So, I've left it in place, anyway. After one other fruitless experiment, which I did remove, the only thing I could think of doing was to read FRAGMENT.C, very closely, again. The only thing(s) I could find really bothersome were the memcpy( ) calls in fragment( )'s if (data_start) and if (got_hole) clauses. These guys could be wreaking the havoc I was seeing. If data_start ever got too big, for example. So, I added the following to FRAGMENT.C: Near the top: /* Extended to ignore packets that would overrun a buffer, after being moved /* to the data_start offset. /* Fred C. Macall 26 June 2006. /* The if (data_start) clause's memcpy( ) call changed to a memmove( ) call /* in order to avoid a possible problem with overlapping source and /* destination data areas. /* Fred C. Macall 28 June 2006. */ Near the rest of the #define(s): #define BUFSIZE 1600 /* Must match BUFSIZE in ASMPKT.ASM. */ Following: more_frags = ip->frags & IP_MF ; /* See if the given packet, whether found or not, contains no data /* or will overrun its buffer once moved into position. /* If so, can't use it! */ if ((data_length <= 0) || ((intel16(ip->length) + data_start + (more_frags ? sizeof(hole_descr) : 0)) > (BUFSIZE - _pktipofs))) { pkt_buf_release((char *) ip) ; return(0) ; } And, I've changed memcpy( to memmove( in the if (data_start) clause. (The memcpy( ) in the if (got_hole) clause didn't need changing. Because, the data areas it deals with shouldn't be overlapping.) Well, believe it or not, I haven't seen another DosLynx failure since making these FRAGMENT.C updates! I think these updates must work by dropping a troublesome packet, now and then. However, I haven't noticed any drop in throughput as a result. Apparently, the troublesome packets are few and far between. And, the TCP/IP protocol must provide way(s) to work around the loss of these troublesome packets. It will be interesting to investigate these exceptions in some detail. A small increase in BUFSIZE, for example, might be found useful. Of course, it will also be of interest to learn why the DosLynx Protected Mode version has seemed to be so much more vulnerable, than the Real Mode version, to this issue. Updated Score As explained under the heading: Keeping Score, in the history.txt for DosLynx v0.20b, I am maintaining an informal written list of DosLynx issues and their resolutions. In addition to the issues it's always had, this list now includes issues that have come along in connection with the DosLynx Protected Mode version. At the time of this writing, for the release of DosLynx v0.32b (at the end of July 2006), my list has about 483 issues. Of these, about 345 (well over two thirds) have been resolved or ameliorated. This leaves a total of about 138 issues pending. If you will look ahead to the next section for a moment, you may note that several of the pending issues include the parenthetical observation: "This is hardly an issue with the DosLynx Protected Mode version." As far as users of the DosLynx Protected Mode version are concerned, the issues to which this observation applies aren't really pending issues. On the other hand, the DosLynx Protected Mode version does have a few issues, of its own, that don't apply to the Real Mode version. A study identifying issues that don't apply to both versions finds about 132 issues pending for the Real Mode version and about 129 issues pending for the Protected Mode version. In the next section, I'll list a few of the 138 pending issues that haven't been mentioned above. To Do With the DosLynx Protected Mode version well on its way, pressure is building to implement some of the enhancements listed in the top five entries in the following list. I hope to be able to do something about one or more of these "big five" issues in the next year. Here is a summary of some of the pending issues not discussed anywhere above: - Provide https/SSL support. (This is expected by many Web servers that support data entry.) - Provide cookies support. (This, too, may be expected for data entry.) - Provide Login (original AUTHINFO) support for the news client? - Support the HTML Form