		Implementation Notes
		       on the
		    Xgopher client


These notes describe Xgopher version 1.3, completed in May 1993.
The implementor and author of these notes can be contacted at:

	Allan Tuchman
	Computing and Communications Services Office (CCSO)
	University of Illinois at Urbana-Champaign
	1304 W. Springfield Ave.
	Urbana, Illinois   61801
	USA

	(217) 244-0048
	a-tuchman@uiuc.edu


Source Organization
-------------------
The xgopher source files are organized by function.  They are:

    xgopher.c - main program, initialize X, set up initial request.
    item.c    - manage the data fields for gopher items
    itemList.c- create and manage the data structures for gopher items
    dir.c     - manage the data fields for gopher directories
    dirList.c - create and manage the data structures for gopher directories
    markList.c- create and manage the bookmark list of gopher items
    util.c    - does gopher processing, get and process gopher requests
    misc.c    - misc things like time functions that may be host dependent
    net.c     - open, read, and write from a network connection
    help.c    - manage help file data.
    bkmkfile.c- manage bookmark file load and save
    itemInfo.c- obtain info about a gopher item or directory
    subst.c   - perform printf-like substitutions of gopher item data
    jobs.c    - keep track of jobs spawned by Xgopher
    sc_*.c    - gopher item class processing for each subclass of gopher item

   ------  No file above here has any connection to the X window system -----

    gui.c     - interface between the previous files and X functions
    resources.c- retrieve application resources
    cso.c     - create, manage, and process requests for CSO name servers
    index.c   - create and manage panel to get keywords for index searches
    panel.c   - create and manage the main xgopher panel
    error.c   - create and manage the error pop up
    save.c    - create and manage the file save pop up and functions
    options.c - create and manage the pop up for changing run-time options
    single.c  - create and manage the pop up for entering a special item
    text.c    - create and manage the text display pop ups
    version.c - create and manage the version information pop up
    status.c  - create and manage the status popup window
    KeyWSink.c- subclass of AsciiSink widget that can highlight
		selected keywords

The include files are used to provide functions definitions, 
configuration options, data structure declarations, share data,
and define bitmaps.  They are:

    conf.h       - configuration parameters
    gopher.h     - data structure definitions for items and directories
    resources.h  - the definition of the application resources structure
    appres.h     - the global definition of the app. resources structure
    popres.h     - subresources for popup window positioning
    typeres.h    - subresources for extended type definition
    globals.h    - a couple of variables, symbolic constants, and macros
    oneLine.h    - text widget translations to enable single line edit mode
    osdep.h      - attempt to isolate some OS dependencies for include files.
    MIT_Xosdefs.h- X11R5 OS dependency code from MIT.
    MIT_Xos.h    - X11R5 OS dependency header code from MIT.
    version.h    - Xgopher version info and display text
    xglobals.h   - shared values defined in the X files
    listP.h      - resources used only in {mark,dir)List.c (from resources.c)
    panel.h      - public header file and macros for panel.c
    compatR4.h   - X11R4 compatibility macros
    text.h       - data for text.c
    sc_*P.h      - private header for each subclass of gopher item
    KeyWSink.h   - public header file for KeyWSink widget
    KeyWSinkP.h  - private header file for KeyWSink widget
    bitmaps/*    - contains bitmaps and icons.

    The following are all simple function declaration header files:
           item.h, itemList.c, dir.h, dirList.h, markList.h,
           gui.h, misc.h,  net.h,  util.h, help.h,  cso.h, index.h, error.h,
           bkmkfile.h, itemInfo.h, options.h, single.h, jobs.h, status.h,
           subst.h, sc_*.h


Other files:

    Imakefile      - used to generate a Makefile
    Makefile.NoNo  - A LAST RESORT sample Makefile for those without Imake
    README         - documentation file - SHOULD READ BEFORE INSTALLATION
    xgopher.help   - a sample help file
    xgopher.man    - a Unix manual page for xgopher
    Xgopher.ad     - the applications defaults file.  It MUST be used!
    Xgopher-color.ad - applications color resources file.
    Xgopher-complete.ad - combination of the above two files.
    Xgopher-secure.ad - resources file used for public Xgopher kiosk with
                        a touch screen.
    Xgopher-allExtend.ad - Sample app-defaults with lots of extended types.

Files in ./Documents:
    Changes        - list of changes since Xgopher 1.2
    Release_Notes  - documentation file - describes changes/features of this
		     version of Xgopher.
    Edits          - notes on string editing for command strings
    Extended-Types - detailed notes on use of extended types, with examples
    Install-Customization -
                     Helps the installer customize certain functions
                     of Xgopher, including where to find some external
                     programs that may be useful.
    Popups         - Details on how to use the popup positioning resources
    Porting        - Notes on porting Xgopher to other platforms.
    Implementation - documentation file interesting to the programmer
    Sun-names      - Some details on problems that Sun's may have in
                     resolving host names.
    Sunlib-rebuild - notes on rebuilding a Sun library to help find
                     a name server.
    OW3-site.def   - a configuration file used for compiling with Sun's
		     OpenWindows, release 3.
    OW3-xmkmf.patch- an optional fix to Sun's OpenWindows xmkmf program.


I have tried to keep major operating system dependencies all in the
file misc.c and osdep.h. Different versions of Unix may have slightly
different programming requirements.  These slight variations are handled
through preprocessor directives in the appropriate source files.


Resource Usage
--------------

I have made considerable effort to maintain and reuse every resource
allocated.  Memory for major data structures is never freed back to the
system, but structures that are no longer in use are maintained and reused
again later.  The idea is that it is expensive to get and build
things, but cheap to reuse them.  This philosophy applies to
  . gopher items (the lines you see on the screen and their selector
    information).
  . gopher directories
  . X window text popups
  . Other popups, panels, and help data.
  . Lists created and used to display the X directory and bookmark
    contents lists.


Positioning Popup Windows
-------------------------

Everyone has there own preferences as to where popups should appear.
There are good arguments for having them 1) near the cursor, 2) a
constant position on the main application window, and 3) a constant
location on the screen.

If you want to change popup positions, here's how to do it in the
source program.  Future versions of Xgopher may allow such
preferences in the application defaults file.

Text (and help) displays are not transient windows, and I leave their
placement to the window manager and the user's window manager preferences.
For all transient windows I place them with a single, pretty general
function call.  The call 

    positionPopup(w, from, fromWidget, x, y, hJust, vJust);

is used just before poping-up widget w.  If one wants to change
the pop-up location or policy for a specific widget, one need
only change the parameters to this procedure.  The rest or the
parameters are:

    from  takes it value from the set of symbolic constants:
	  { POS_none, POS_pointer, POS_appPanel, POS_screen }, which
	  do respectively,  no positioning, position at the pointer
	  location, position relative to an application window, or 
	  position relative to the screen.
    
    fromWidget
	  For from=POS_appPanel, this is the widget (window) to position on.
    
    x, y  provide a location in percent across the application window
	  or screen (depending on from).  For example, x=50, y=50
	  represents the center of either the window or the screen.
	
    hJust, vJust
	  are horizontal and vertical justification requirements.  For
	  hJust = 0 the left edge of the popup is positioned at x;
	  hJust = 1 the center of the popup is positioned at x;
	  hJust = 2 the right edge of the popup is positioned at x.
	  The same is true for vJust, using top, middle, and bottom
	  against y.

	  These justifications do not take into account the size of
	  the window manager decorations, but they're close enough
	  anyway to be pretty useful.

After positioning, positionPopup forces the complete popup to lie
on screen by "shoving" it, if necessary, just enough to get it fully
on the display.


Hacker's Corner
---------------

Using the "Enter Gopher Item" menu item and selecting a directory
but using type=0 (text file), you can capture a raw gopher directory
response into a text file.  I find this useful for debugging and
for documentation.  You can also set type=9 to copy any file in
binary mode.


Differences from Previous Versions of Xgopher
---------------------------------------------

The earliest released versions of Xgopher (Xgopher 1.0, 1.1, and 1.1a)
maintained a notion of a dynamic n-ary tree that the user traversed
through gopher space.  Along with this tree, was the notion of a bookmark
being a "place", and internal node in this tree.  The main gopher data
structures were maintained by the routines in the file list.c.

For better or worse, the Unix curses client defined peoples expectations 
of bookmark behavior, and indeed, the way gopher space was presented.
As such, the entire basic data structure has been changed at Xgopher 1.2.
The n-ary tree has been replaced with a directory stack.  Most important,
bookmarks are no longer places (directories), but things (items).  Of
course, an item may be a directory.  The file list.c has been replaced
with 5 smaller files (item.c, itemList.c, dir.c, dirList.c, markList.c).

Xgopher 1.3 introduced significant changes in the way gopher item
classes were handled internally, giving far better maintenance control.
Extended types make source changes unnecessary for adding many new
gopher types for special purposes, testing, and local customization.


Subclass Implementation for Gopher Items
----------------------------------------

=== This section is totally changed for Xgopher 1.3 ===


To implement a sort of subclass using standard C, I introduced
to the base class a new field, sc, a pointer to a subclass
structure.  For the base class, this points to a structure of
default (null or unknown) data and methods.

I chose this method instead of one like X uses for widget 
subclassing because 1) I want to be able to reuse items with
different subtypes without incurring the expense of freeing
and reallocating them; 2) The subclass records are all of the
same description; and 3) I don't need to go very deep in
subclassing.

I also didn't use a function table as would be generated by
C++, again, because I have a simple, constant subclass record
structure, and the type (subclass) of an item will not change
over its useful lifetime.

So, scInfo (struct subClassInfoStruct) contains a few constant
strings and function references that will be constant for each
item of that class.


Adding a New Internal Item Type to Xgopher
------------------------------------------

To add a new class:

1. create the private class record in a header file named

	sc_<type>P.h

   It should start out something like this:

	/* sc_<type>P.h
	   gopher item subclass: <type> */
	
	/* ----- subclass record definition ----- */
	
	scInfo	<type>Subclass = {
			"<description of type>",
			prefix<Type>,
			nullHostList,
			checkAccess,
			GI_copyItemToFile,
			copyTypeBinaryEOF,
			GI_noProcess,
			GI<type>Init,
			GI_done,
			GI<type>restart
		};

   Also create a public class header with the function definitions.

   You can model both of these files on an existing subclass.

2. Add the prefix<Type> resource by modifying
	
	resources.h
	resources.c
	prefixP.h
	conf.h		for the default (PREFIX_<TYPE>)

   Follow the examples by looking for "prefixDir" in each file, and do the
   same thing for the new type.

3. Add the prefix<Type> resource to Xgopher.ad (again, look for the area
   around prefixDir and do the same.

4. Modify util.c:
   . Add the new header file with all the other "sc_something.h" includes.
   . Add the new type character and subclass record to the list defined by:

	static gopherTypeClass     types[] = {
		:
		:
	};


===========================================================================
There now a new type defined in Xgopher, but with only default behavior.
It can only be accessed by a "copy", not a "fetch".  Copy will be in 
binary (not ascii).  The only access limits imposed my be against ftp
(no host access lists).  And there is not special processing upon a
restart command.

Time to customize this item.  If it is very similar in behavior to another
gopher type, it is a good idea to look at the subclass methods for that
other type (in the sc_other.[hc] files before proceding.
===========================================================================

5. For each of the following routines, write new versions if the 
   default behavior is not acceptable.
   . The procedures should be placed in the file sc_<type>.c
   . The procedures should be declared static unless they are
     callbacks or some other unusual circumstance dictates.
   . Function declaration headers for these procedures should be
     included in sc_<type>.h before the subclass record is defined.
   . The names below are suggested names.

   A. checkAccess	- suggested name is GI<Type>_checkAccess
      Any checks to limit access to an item by host, domain, ftp, 
      or other criteria.  The default procedure often suffices.

   B. copyItemToFile	- suggested name is GI<Type>_copyItem
      Copy processing procedure for this item type when the "copy
      selection to file" button is pressed.  The default procedures
      GI_copyItemToFile or GI_noCopyItem often suffice.

   C. process		- suggested name is GI<Type>_process
      The normal processing procedure for this item type when the
      "fetch selection" button is pressed.  Either GI_noProcess is
      useful or a custom procedure is written for this method.
      Process procedures are responsible for keeping the user
      informed about what's going on - the current status of
      their request.  Although not necessary for correct function,
      it is nice to provide some feedback.  The status popup
      shared by other classes may be used.

   D. copy		- suggested name is copyBin, copyAscii, or
			  GI<Type>_copy
      Normally, one of the two existing procedures copyBin or copyAscii
      is used.

   E. restart		- suggested name is GI<Type>_restart
      This is a class-level restart.  It is used for example, to pop
      down any windows associated with a CSO name server, an index
      search query, or text windows.


Gopher Directory Data Structure
-------------------------------

=== This section is totally changed as of Xgopher 1.2 ===

The gopher directories are maintained in a stack.  The stack is
implemented as modified last-in-first-out (LIFO) data structure.
The modification is that a "pop" operation decrements the top-of-stack
pointer as usual, but the previous top-of-stack item is not yet freed
or removed from the stack.  This occurs when the next "push" operation
occurs.  This allows the stack to be traversed backward, then forward
again (even though the forward traversal is not normal stack behavior).
Strange? Perhaps; but it doesn't cost anything to do it this way, and
it allows one to recover easily from a mistaken "go-back" type of command.
It is also cheaper for the user, since the contents of the directories
are maintained (not refetched) as long as they are maintained in the
stack.

The stack, then, may look like this:

 firstDir                              currentDir--+
   |                                               |
   |                                               V
   |  +-----+------+           +-----+------+   +-----+------+   +-----+------+
   +->| dir | next+|--> ... -->| dir | next+|-->| dir | next+|-->| dir | NULL |
      |  1  |      |           | N-2 |      |   | N-1 |      |   |  N  |      |
      +-----+------+           +-----+------+   +-----+------+   +-----+------+

currentDir normally would point as the last directory in the list.
In the diagram above, the user has selected the "previous directory"
function to return one level back.

If the user now selects anything except "move forward" (NOT A FUNCTION
DEFINED BY DEFAULT), then this new selection will replace directory N
and all of its successors.  Each directory from N on is released.

Once a directory is released, the directory data structure
is removed from the stack and moved back to a "free list".

Gopher items are saved (cached) with the directory until either the
directory is released or they become stale.  A time field in the directory
structure identifies the time that the directory contents were
last fetched.  Whenever the contents are needed, the time is
checked, and if some user-specified threshold of elapsed time
is exceeded, then the directory contents are freed and re-requested
from the server.


	Directory Node structure (gopherDir)

                                   gopherItem
        			        .
        			       / \
        			        |
        			        |
        	   +----------+--------------+------+
      gopherDir <--|+previous | selectorItem | next+|----> gopherDir
        	   +----------+--------------+------+
        	   | created  | contents            |
        	   +----------+---------------------+
        	                        |
        	                        |
        			       \ /                
        			        .
                                 gopherItemList


A gopherItemList is simply a first/last pointer structure:

	  +--------+
	  | first +|---> gopherItem
	  +--------+
	  | last  +|---> gopherItem
	  +--------+

And the gopherItem structure is:

	  +------+------+------+------+
	  | type | name | path | next+|--->
	  +------+------+------+------+
	  | host | port | plus        |
	  +------+------+-------------+


Button Sensitivity
------------------

The buttons are set sensitive according to the following conditions

 . Fetch:	if ANYTHING selected
 . Copy:	if ANYTHING selected
 . Previous:	if previousDir != NULL
 . RemoveMark:	if ANY MARK selected
 . RemoveAllMarks:	if markListLen != 0
 . LoadMarks:	if BookmarkFile != NULL and != empty string
 . SaveMarks:	if BookmarkFile != NULL and != empty string and
                   allowBookmarkSave and markListLen != 0
 . Info:	if ANYTHING selected ==> label = "info on item"
                else if currentDir exists ==> label = "info on directory"
 . Mark:	if ANY NON-MARK selected ==> label = "mark item"
                else if currentDir exists ==> label = "mark directory"


Widget Tree
-----------

If you want to better customize some of the widgets or perhaps modify
Xgopher, a widget tree is helpful.  This one isn't beautiful, but
it was up to date as of the release of Xgopher 1.3.
Each line contains first the widget class, then the instance name.
Indentation shows the parent-child relationships.

Xgopher  xgopher
	Paned  gopherPanel
		Form  statusForm
			Command  quit
			MenuButton  other
				SimpleMenu  otherActionsMenu
					SmeBSB  copy
					SmeBSB  unmarkAll
					SmeBSB  loadMarks
					SmeBSB  saveMarks
					SmeBSB  options
					SmeBSB  oneItem
					SmeBSB  version
					SmeBSB  restart
			Command  help
			Label  status
		Form  directoryForm
			Label  directoryTitle
			Viewport  directoryView
				Core  clip
				Scrollbar  vertical
				List  directory
		Box  goBox
			Command  fetch
			Command  info
			Command  up
			Simple  spacer
			Command  mark
			Command  unmark
		Form  bookmarkForm
			Label  bookmarkTitle
			Viewport  bookmarkView
				Core  clip
				Scrollbar  vertical
				List  bookmark
		Grip  grip
		Grip  grip
	TransientShell  errorDialogShell
		Dialog  errorDialog
			Label  icon
			Label  label
			Command  ok
	TransientShell  optionsPanel
		Form  optionsForm
			Box  buttonBox
				Command  done
				Command  cancel
				Command  help
			Form  itemsForm
				Box  showWhatBox
					Toggle  showWhat
					Label  showWhatLabel
				Box  appendBkBox
					Toggle  appendBk
					Label  appendBkLabel
				Box  loadBkBox
					Toggle  loadBk
					Label  loadBkLabel
				Box  resetBox
					Toggle  reset
					Label  resetLabel
				Form  bkSaveForm
					Label  bkSaveLabel
					Text  bkSave
				Form  printCmdForm
					Label  printCmdLabel
					Text  printCmd
				Form  imageCmdForm
					Label  imageCmdLabel
					Text  imageCmd
				Form  telCmdForm
					Label  telCmdLabel
					Text  telCmd
				Form  t3270CmdForm
					Label  t3270CmdLabel
					Text  t3270Cmd
	TransientShell  singlePanel
		Form  singleForm
			Box  buttonBox
				Command  done
				Command  cancel
				Command  clear
				Command  mark
				Command  help
			Form  itemsForm
				Form  giTypeForm
					Label  giTypeLabel
					Text  giType
				Form  giNameForm
					Label  giNameLabel
					Text  giName
				Form  giPathForm
					Label  giPathLabel
					Text  giPath
				Form  giHostForm
					Label  giHostLabel
					Text  giHost
				Form  giPortForm
					Label  giPortLabel
					Text  giPort
	TransientShell  infoDialogShell
		Dialog  infoDialog
			Label  icon
			Label  label
			Command  ok
	TopLevelShell  csoShell
		Form  csoForm
			Label  nameServer
			Command  csoDone
			SimpleMenu  csoFieldsMenu
				SmeBSB  Default
				SmeBSB  Lookup
				SmeBSB  Indexed
				SmeBSB  Public
			MenuButton  csoFields
			Command  csoHelp
			Label  csoQueryLabel
			Text  csoQueryText
			Command  csoDoQuery
			Command  csoClearQuery
			Command  csoClearText
			Text  csoText
	TransientShell  indexShell
		Form  indexForm
			Command  indexDoIndex
			Command  indexCancel
			Command  indexHelp
			Label  indexLabel
			Text  indexQueryText
	TransientShell  saveShell
		Form  saveForm
			Label  dirLabel
			Text  dirPath
			Label  saveLabel1
			Label  saveLabel2
			Text  fileName
			Label  fileErrMessage
			Command  ok
			Command  cancel
			Command  chdir
			Command  help
		TransientShell  cdShell
			Form  cdForm
				Label  cdLabel
				Text  cdPathName
				Label  cdErrMessage
				Command  ok
				Command  cancel
				Command  help
		TransientShell  dupFileShell
			Form  dupFileForm
				Label  label1
				Label  labelFile
				Label  label2
				Command  ok
				Command  cancel
				Command  append
				Command  change
				Command  help


Special thanks
------------------

I want to thank everyone who took the time to send me comments, suggestions,
and constructive criticism on previous versions of Xgopher.
Much of the Xgopher 1.3 change was motivated by this feedback.
Also, thanks to the several people who helped beta test this release.

Of course, the present author assumes responsibility for any
problems introduced.
