Fuck.  For PC support, this must be in the distribution.
diff --git a/Lib/dos_8x3/socketse.py b/Lib/dos_8x3/socketse.py
new file mode 100755
index 0000000..9a646ab
--- /dev/null
+++ b/Lib/dos_8x3/socketse.py
@@ -0,0 +1,413 @@
+"""Generic socket server classes.
+
+This module tries to capture the various aspects of defining a server:
+
+- address family:
+	- AF_INET: IP (Internet Protocol) sockets (default)
+	- AF_UNIX: Unix domain sockets
+	- others, e.g. AF_DECNET are conceivable (see <socket.h>
+- socket type:
+	- SOCK_STREAM (reliable stream, e.g. TCP)
+	- SOCK_DGRAM (datagrams, e.g. UDP)
+- client address verification before further looking at the request
+	(This is actually a hook for any processing that needs to look
+	 at the request before anything else, e.g. logging)
+- how to handle multiple requests:
+	- synchronous (one request is handled at a time)
+	- forking (each request is handled by a new process)
+	- threading (each request is handled by a new thread)
+
+The classes in this module favor the server type that is simplest to
+write: a synchronous TCP/IP server.  This is bad class design, but
+save some typing.  (There's also the issue that a deep class hierarchy
+slows down method lookups.)
+
+There are four classes in an inheritance diagram that represent
+synchronous servers of four types:
+
+	+-----------+        +------------------+
+	| TCPServer |------->| UnixStreamServer |
+	+-----------+        +------------------+
+	      |
+	      v
+	+-----------+        +--------------------+
+	| UDPServer |------->| UnixDatagramServer |
+	+-----------+        +--------------------+
+
+(Note that UnixDatagramServer derives from UDPServer, not from
+UnixStreamServer -- the only difference between an IP and a Unix
+stream server is the address family, which is simply repeated in both
+unix server classes.)
+
+Forking and threading versions of each type of server can be created
+using the ForkingServer and ThreadingServer mix-in classes.  For
+instance, a threading UDP server class is created as follows:
+
+	class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+
+(The Mix-in class must come first, since it overrides a method defined
+in UDPServer!)
+
+To implement a service, you must derive a class from
+BaseRequestHandler and redefine its handle() method.  You can then run
+various versions of the service by combining one of the server classes
+with your request handler class.
+
+The request handler class must be different for datagram or stream
+services.  This can be hidden by using the mix-in request handler
+classes StreamRequestHandler or DatagramRequestHandler.
+
+Of course, you still have to use your head!
+
+For instance, it makes no sense to use a forking server if the service
+contains state in memory that can be modified by requests (since the
+modifications in the child process would never reach the initial state
+kept in the parent process and passed to each child).  In this case,
+you can use a threading server, but you will probably have to use
+locks to avoid two requests that come in nearly simultaneous to apply
+conflicting changes to the server state.
+
+On the other hand, if you are building e.g. an HTTP server, where all
+data is stored externally (e.g. in the file system), a synchronous
+class will essentially render the service "deaf" while one request is
+being handled -- which may be for a very long time if a client is slow
+to reqd all the data it has requested.  Here a threading or forking
+server is appropriate.
+
+In some cases, it may be appropriate to process part of a request
+synchronously, but to finish processing in a forked child depending on
+the request data.  This can be implemented by using a synchronous
+server and doing an explicit fork in the request handler class's
+handle() method.
+
+Another approach to handling multiple simultaneous requests in an
+environment that supports neither threads nor fork (or where these are
+too expensive or inappropriate for the service) is to maintain an
+explicit table of partially finished requests and to use select() to
+decide which request to work on next (or whether to handle a new
+incoming request).  This is particularly important for stream services
+where each client can potentially be connected for a long time (if
+threads or subprocesses can't be used).
+
+Future work:
+- Standard classes for Sun RPC (which uses either UDP or TCP)
+- Standard mix-in classes to implement various authentication
+  and encryption schemes
+- Standard framework for select-based multiplexing
+
+XXX Open problems:
+- What to do with out-of-band data?
+
+"""
+
+
+__version__ = "0.2"
+
+
+import socket
+import sys
+import os
+
+
+class TCPServer:
+
+    """Base class for various socket-based server classes.
+
+    Defaults to synchronous IP stream (i.e., TCP).
+
+    Methods for the caller:
+
+    - __init__(server_address, RequestHandlerClass)
+    - serve_forever()
+    - handle_request()	# if you don't use serve_forever()
+    - fileno() -> int	# for select()
+
+    Methods that may be overridden:
+
+    - server_bind()
+    - server_activate()
+    - get_request() -> request, client_address
+    - verify_request(request, client_address)
+    - process_request(request, client_address)
+    - handle_error()
+
+    Methods for derived classes:
+
+    - finish_request(request, client_address)
+
+    Class variables that may be overridden by derived classes or
+    instances:
+
+    - address_family
+    - socket_type
+    - request_queue_size (only for stream sockets)
+
+    Instance variables:
+
+    - server_address
+    - RequestHandlerClass
+    - socket
+
+    """
+
+    address_family = socket.AF_INET
+
+    socket_type = socket.SOCK_STREAM
+
+    request_queue_size = 5
+
+    def __init__(self, server_address, RequestHandlerClass):
+	"""Constructor.  May be extended, do not override."""
+	self.server_address = server_address
+	self.RequestHandlerClass = RequestHandlerClass
+	self.socket = socket.socket(self.address_family,
+				    self.socket_type)
+	self.server_bind()
+	self.server_activate()
+
+    def server_bind(self):
+	"""Called by constructor to bind the socket.
+
+	May be overridden.
+
+	"""
+	self.socket.bind(self.server_address)
+
+    def server_activate(self):
+	"""Called by constructor to activate the server.
+
+	May be overridden.
+
+	"""
+	self.socket.listen(self.request_queue_size)
+
+    def fileno(self):
+	"""Return socket file number.
+
+	Interface required by select().
+
+	"""
+	return self.socket.fileno()
+
+    def serve_forever(self):
+	"""Handle one request at a time until doomsday."""
+	while 1:
+	    self.handle_request()
+
+    # The distinction between handling, getting, processing and
+    # finishing a request is fairly arbitrary.  Remember:
+    #
+    # - handle_request() is the top-level call.  It calls
+    #   get_request(), verify_request() and process_request()
+    # - get_request() is different for stream or datagram sockets
+    # - process_request() is the place that may fork a new process
+    #   or create a new thread to finish the request
+    # - finish_request() instantiates the request handler class;
+    #   this constructor will handle the request all by itself
+
+    def handle_request(self):
+	"""Handle one request, possibly blocking."""
+	request, client_address = self.get_request()
+	if self.verify_request(request, client_address):
+	    try:
+		self.process_request(request, client_address)
+	    except:
+		self.handle_error(request, client_address)
+
+    def get_request(self):
+	"""Get the request and client address from the socket.
+
+	May be overridden.
+
+	"""
+	return self.socket.accept()
+
+    def verify_request(self, request, client_address):
+	"""Verify the request.  May be overridden.
+
+	Return true if we should proceed with this request.
+
+	"""
+	return 1
+
+    def process_request(self, request, client_address):
+	"""Call finish_request.
+
+	Overridden by ForkingMixIn and ThreadingMixIn.
+
+	"""
+	self.finish_request(request, client_address)
+
+    def finish_request(self, request, client_address):
+	"""Finish one request by instantiating RequestHandlerClass."""
+	self.RequestHandlerClass(request, client_address, self)
+
+    def handle_error(self, request, client_address):
+	"""Handle an error gracefully.  May be overridden.
+
+	The default is to print a traceback and continue.
+
+	"""
+	exc, value, tb = sys.exc_type, sys.exc_value, sys.exc_traceback
+	print '-'*40
+	print 'Exception happened during processing of request from',
+	print client_address
+	import traceback
+	traceback.print_exception(exc, value, tb)
+	print '-'*40
+
+
+class UDPServer(TCPServer):
+
+    """UDP server class."""
+
+    socket_type = socket.SOCK_DGRAM
+
+    max_packet_size = 8192
+
+    def get_request(self):
+	return self.socket.recvfrom(max_packet_size)
+
+
+if hasattr(socket, 'AF_UNIX'):
+
+    class UnixStreamServer(TCPServer):
+
+	address_family = socket.AF_UNIX
+
+
+    class UnixDatagramServer(UDPServer):
+
+	address_family = socket.AF_UNIX
+
+
+class ForkingMixIn:
+
+    """Mix-in class to handle each request in a new process."""
+
+    active_children = None
+
+    def collect_children(self):
+	"""Internal routine to wait for died children."""
+	while self.active_children:
+	    pid, status = os.waitpid(0, os.WNOHANG)
+	    if not pid: break
+	    self.active_children.remove(pid)
+
+    def process_request(self, request, client_address):
+	"""Fork a new subprocess to process the request."""
+	self.collect_children()
+	pid = os.fork()
+	if pid:
+	    # Parent process
+	    if self.active_children is None:
+		self.active_children = []
+	    self.active_children.append(pid)
+	    return
+	else:
+	    # Child process.
+	    # This must never return, hence os._exit()!
+	    try:
+		self.finish_request(request, client_address)
+		os._exit(0)
+	    except:
+		try:
+		    self.handle_error(request,
+				      client_address)
+		finally:
+		    os._exit(1)
+
+
+class ThreadingMixIn:
+
+    """Mix-in class to handle each request in a new thread."""
+
+    def process_request(self, request, client_address):
+	"""Start a new thread to process the request."""
+	import thread
+	thread.start_new_thread(self.finish_request,
+				(request, client_address))
+
+
+class ForkingUDPServer(ForkingMixIn, UDPServer): pass
+class ForkingTCPServer(ForkingMixIn, TCPServer): pass
+
+class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
+
+
+class BaseRequestHandler:
+
+    """Base class for request handler classes.
+
+    This class is instantiated for each request to be handled.  The
+    constructor sets the instance variables request, client_address
+    and server, and then calls the handle() method.  To implement a
+    specific service, all you need to do is to derive a class which
+    defines a handle() method.
+
+    The handle() method can find the request as self.request, the
+    client address as self.client_request, and the server (in case it
+    needs access to per-server information) as self.server.  Since a
+    separate instance is created for each request, the handle() method
+    can define arbitrary other instance variariables.
+
+    """
+
+    def __init__(self, request, client_address, server):
+	self.request = request
+	self.client_address = client_address
+	self.server = server
+	try:
+	    self.setup()
+	    self.handle()
+	    self.finish()
+	finally:
+	    sys.exc_traceback = None	# Help garbage collection
+
+    def setup(self):
+	pass
+
+    def __del__(self):
+	pass
+
+    def handle(self):
+	pass
+
+    def finish(self):
+	pass
+
+
+# The following two classes make it possible to use the same service
+# class for stream or datagram servers.
+# Each class sets up these instance variables:
+# - rfile: a file object from which receives the request is read
+# - wfile: a file object to which the reply is written
+# When the handle() method returns, wfile is flushed properly
+
+
+class StreamRequestHandler(BaseRequestHandler):
+
+    """Define self.rfile and self.wfile for stream sockets."""
+
+    def setup(self):
+	self.connection = self.request
+	self.rfile = self.connection.makefile('rb')
+	self.wfile = self.connection.makefile('wb', 0)
+
+    def finish(self):
+	self.wfile.flush()
+
+
+class DatagramRequestHandler(BaseRequestHandler):
+
+    """Define self.rfile and self.wfile for datagram sockets."""
+
+    def setup(self):
+	import StringIO
+	self.packet, self.socket = self.request
+	self.rfile = StringIO.StringIO(self.packet)
+	self.wfile = StringIO.StringIO(self.packet)
+
+    def finish(self):
+	self.socket.send(self.wfile.getvalue())