This page is designed to be viewed by a browser which supports
Netscapes Frames extension. This text will be shown by browsers
which do not support the Frames extension.
'! !
!MetaOptionPage methodsFor: 'as yet unclassified' stamp: 'taj 10/17/97 04:04'!
process: aSession
| page pageLink |
page := HTMLPreformattedPage title: 'Class Categories' session: aSession.
pageLink := PageLink new
page: 'MethodCategoriesPage';
target: 'methodCategories';
yourself.
page add: (pageLink label: 'instance'; value: '#instance'; yourself).
page add: (pageLink label: 'class'; value: '#class'; yourself).
^page code
! !
!MethodCategoriesPage methodsFor: 'as yet unclassified' stamp: 'taj 10/17/97 06:19'!
process: aSession
|pageLink page model metaOptionSet classToBrowse n|
model := aSession data.
metaOptionSet := false.
self linkValue = '1instance' ifTrue: [model browseMeta: false. metaOptionSet := true].
self linkValue = '1class' ifTrue: [model browseMeta: true. metaOptionSet := true].
page := HTMLPreformattedPage title: 'Method Categories' session: aSession.
pageLink := PageLink new
page: 'MethodsPage';
target: 'methods';
yourself.
metaOptionSet ifFalse: [ model modelClass: (Smalltalk at: self linkValue asSymbol) ].
classToBrowse := model classToBrowse.
page add: classToBrowse printString,NewLine,NewLine.
n := 1.
classToBrowse organization categories do:
[:i| pageLink label: i ; value: i,',',10000 atRandom printString.
n := n + 1.
page add: pageLink; add: NewLine].
^page code! !
!MethodPage methodsFor: 'as yet unclassified' stamp: 'taj 10/17/97 05:52'!
process: aSession
|page model|
model := aSession data.
page := HTMLPage title: 'Methods' session: aSession.
page add: (self fix: (model classToBrowse sourceCodeAt: self linkValue asSymbol)).
^page code! !
!MethodsPage methodsFor: 'as yet unclassified' stamp: 'taj 10/18/97 01:59'!
process: aSession
|pageLink page model classString fixed|
model := aSession data.
classString := (self linkValue findTokens: ',') at: 1.
page := HTMLPreformattedPage title: 'Methods' session: aSession.
pageLink := PageLink new
page: 'MethodPage';
target: 'lowerPane';
yourself.
page add: classString,NewLine,NewLine.
(model classToBrowse organization listAtCategoryNamed: classString asSymbol) do:
[:i|
fixed := self fix: i.
pageLink label: fixed ; value: fixed.
page add: pageLink; add: NewLine].
^page code
! !
!ProductPage methodsFor: 'as yet unclassified' stamp: 'taj 8/3/97 19:57'!
process: session
|page shopper department product basket|
shopper := session data.
basket := shopper basket.
department := shopper department.
product := shopper store productUsingId: self linkValue.
shopper lookingAt: product.
page := HTMLPage title: product name session: session.
page
add: product name newLine;
add: product description newLine;
add: product id,' $',product price printString newLine newLine;
add: 'What would you like to do now?' newLine newLine.
(basket includes: product)
ifTrue:
[page
add:
('Put another copy in your basket'
linkToPage: 'AddToBasketPage'
value: product id);
add: NewLine;
add:
('Return a copy to the shelf'
linkToPage: 'RemoveFromBasketPage'
value: product id);
add: NewLine]
ifFalse:
[page
add: ('Put a copy in your basket'
linkToPage: 'AddToBasketPage'
value: product id);
add: NewLine].
page add: NewLine.
shopper isLookingInBasket
ifTrue: [page add: ('Back to Inventory' linkToPage: 'BasketPage')]
ifFalse:
[page
add: ('Continue browsing the ',department description
linkToPage: 'DepartmentPage' value: department id);
add: NewLine.
page add: ('Leave this department'
linkToPage: shopper store pageClass printString).
].
^page code
! !
!RemoveFromBasketPage methodsFor: 'as yet unclassified' stamp: 'taj 8/3/97 18:07'!
process: session
|page shopper basket product|
shopper := session data.
basket := shopper basket.
product := shopper lookingAt.
basket remove: product.
page := HTMLPage title: product name,' rejected' session: session.
page add: 'You place a copy of ', product name,' back on the shelf.'.
page add: ('OK' buttonLinkToPage: 'ProductPage' value: product id).
^page code.! !
!RPNCalculatorPage methodsFor: 'from WebtalkPage' stamp: 'taj 10/17/97 06:44'!
process: session
"this method should be broken up, but has remained monolithic
so that i can have a complete demo in one method"
| page form calculator |
"process keystroke"
session isNew
ifTrue:
[calculator _ RPNCalculator new.
session data: calculator.]
ifFalse:
[calculator _ session data.
self entry ~= '' ifTrue: [calculator push: self entry asNumber].
(self clicked: 'enter') ifTrue: [self entry = '' ifTrue: [calculator dup]].
(self clicked: 'drop') ifTrue: [calculator drop].
(self clicked: 'add') ifTrue: [calculator add].
(self clicked: 'subtract') ifTrue: [calculator subtract].
(self clicked: 'divide') ifTrue: [calculator divide].
(self clicked: 'multiply') ifTrue: [calculator multiply].
(self clicked: 'float') ifTrue: [calculator float].
(self clicked: 'rational') ifTrue: [calculator rational]].
"generate new html page, add header"
page _ HTMLPage title: 'Smalltalk RPN Calculator' session: session.
page add: 'Smalltalk RPN Calculator' heading2.
page add: HorizontalRule newLine.
"add the stack"
calculator stack reversed do: [:line | page add: line printString rightAligned].
page add: HorizontalRule newLine.
"add the buttons (with a form)"
form _ HTMLForm nextPage: 'RPNCalculatorPage'.
form add:
(FormEntryField
name: 'entry'
value: ''
length: 20) rightAligned newLine.
form add:
((FormSubmitButton name: 'enter' label: 'Enter'),
(FormSubmitButton name: 'drop' label: 'Drop') , ' ' ,
(FormSubmitButton name: 'add' label: ' + ') ,
(FormSubmitButton name: 'subtract' label: ' - ') ,
(FormSubmitButton name: 'multiply' label: ' * ') ,
(FormSubmitButton name: 'divide' label: ' / ') , ' ' ,
(FormSubmitButton name: 'float' label: 'Float') ,
(FormSubmitButton name: 'rational' label: 'Rational')) rightAligned.
page add: form.
page add: NewLine.
^ page code! !
!StorePage methodsFor: 'as yet unclassified' stamp: 'taj 8/2/97 02:22'!
pageToExitTo
^self subclassResponsibility! !
!StorePage methodsFor: 'as yet unclassified' stamp: 'taj 10/17/97 06:49'!
process: session
|page shopper|
shopper := self shopper: session.
shopper department: nil.
shopper lookingInBasket: false.
page := HTMLPage title: shopper store description session: session.
page
add: 'You are standing in the ',shopper store description,'.';
add: NewLine;
add: shopper inventoryDescription;
add: NewLine;
add: 'What would you like to do now?' newLine newLine.
shopper store departments do:
[:dep| page
add: ('Enter the ', dep description linkToPage: 'DepartmentPage' value: dep id );
add: NewLine].
page add: NewLine.
shopper basket itemCount > 0
ifTrue:
[page
add: ('Look in your basket' linkToPage: 'BasketPage');
add: NewLine;
add: ('Empty your basket' linkToPage: 'EmptyBasketPage');
add: NewLine;
add: NewLine;
add: ('Check out' linkToPage: 'CheckoutPage')]
ifFalse:
["page
add: ('Leave the store' linkToPage: self pageToExitTo)"].
^page code
! !
!StorePage methodsFor: 'as yet unclassified' stamp: 'taj 7/29/97 09:21'!
shopper: aSession
self subclassResponsibility! !
!SqueakStorePage methodsFor: 'as yet unclassified' stamp: 'taj 8/2/97 02:21'!
pageToExitTo
^'MainTestPage' ! !
!SqueakStorePage methodsFor: 'as yet unclassified' stamp: 'taj 7/29/97 09:22'!
shopper: session
|shopper|
session isNew
ifTrue:
[shopper := Shopper new store: SqueakStore current; yourself.
session data: shopper]
ifFalse: [shopper := session data].
^shopper
! !
!SystemBrowserPage methodsFor: 'as yet unclassified' stamp: 'taj 10/18/97 07:08'!
process: aSession
|response|
aSession isNew ifTrue: [aSession data: BrowserModel new].
response :=
'
System Browser
'.
^response copyReplaceAll: '###' with: aSession id printString! !
!WebtalkErrorPage methodsFor: 'private' stamp: 'taj 8/17/97 13:51'!
errorMessage: aString
errorMessage := aString! !
!WebtalkErrorPage methodsFor: 'from WebtalkPage' stamp: 'taj 8/17/97 13:53'!
process: aSession
|html|
html := HTMLPage title: 'Webtalk Processing Error'.
html add: errorMessage.
^html code! !
!WebtalkPage class methodsFor: 'instance creation' stamp: 'taj 10/17/97 06:41'!
default
^MainTestPage ! !
!WebtalkPage class methodsFor: 'instance creation' stamp: 'taj 8/18/97 04:00'!
process: aDictionary log: aLog
|page|
page := self for: aDictionary.
aLog add: page description.
^page processAndCatchErrors "returns HTML code"
! !
!WebtalkPage class methodsFor: 'queries' stamp: 'taj 8/19/97 17:10'!
isEnabled
^true! !
!WebtalkPage class methodsFor: 'private' stamp: 'taj 8/19/97 17:28'!
for: aDictionary
|webtalkClass instance|
webtalkClass := aDictionary at: 'webtalkClass' ifAbsent: [].
webtalkClass notNil ifTrue: [webtalkClass := Smalltalk at: webtalkClass asSymbol ifAbsent: []].
webtalkClass isNil
ifTrue: [instance := WebtalkErrorPage
errorMessage: 'webtalk class ',webtalkClass,' not available']
ifFalse:
[((webtalkClass inheritsFrom: WebtalkPage) and: [webtalkClass isEnabled])
ifFalse: [instance := WebtalkErrorPage
errorMessage: 'webtalk class ',webtalkClass,' not available']].
instance isNil ifTrue: [instance := webtalkClass new].
instance formDictionary: aDictionary.
^instance
! !
!WebtalkErrorPage class methodsFor: 'instance creation' stamp: 'taj 8/17/97 13:51'!
errorMessage: errorMessage
^self new errorMessage: errorMessage! !
WebtalkServer comment:
'needed:
dependence on general execption handling; need to
add it to the system (Object>>error)
permanent connection
list and table HTML generation'!
!WebtalkServer methodsFor: 'from Connection' stamp: 'taj 8/18/97 02:25'!
eventRead: aString
self nextPut: (WebtalkPage process: aString asFormDictionary log: self log).
self close ! !
!WebtalkServer methodsFor: 'from Connection' stamp: 'taj 8/18/97 02:38'!
nextPut: aString
^self write: aString! !
!WebtalkServer methodsFor: 'from Connection' stamp: 'taj 8/18/97 23:48'!
readObjects
|buffer|
buffer:=self llRead: 1.
(buffer at: bufferDataSize) ~= $&
ifTrue: [remnant := buffer copyFrom: 1 to: bufferDataSize]
ifFalse: [readObjects add: (buffer copyFrom: 1 to: bufferDataSize - 1)].
^self.
! !
!WebtalkServer methodsFor: 'private' stamp: 'taj 8/14/97 05:46'!
log
log isNil ifTrue: [log _ Log to: 'log.txt'].
^ log! !
!WebtalkServer class methodsFor: 'port servicing' stamp: 'taj 10/17/97 07:54'!
listeningPortsCount
^5! !
!WebtalkServer class methodsFor: 'port servicing' stamp: 'taj 8/14/97 08:34'!
startService
self service: 4248.
! !
!WebtalkServer class methodsFor: 'webserver cgi script' stamp: 'taj 8/18/97 05:11'!
webtalkPlCgi
^
'#!!/usr/bin/perl
require 5.001;
# webtalk.pl.cgi - the webtalk cgi interface
# (c) 1996 by tim jones
# based on examples by William E. Weinman and Larry Wall
#################
# configuration
#################
$hostname = ''warmspot'';
$webtalkServer = ''wotan'';
$port = 4248;
###############################
# connect to smalltalk server
###############################
use Socket;
$sockaddr = ''S n a4 x8'';
#chop($hostname = `hostname`);
($name, $aliases, $proto) = getprotobyname(''tcp'');
($name, $aliases, $port) = getservbyname($port, ''tcp'') unless $port =~ /^\d+$/;
($name, $aliases, $type, $len, $thisaddr) = gethostbyname($hostname);
($name, $aliases, $type, $len, $thataddr) = gethostbyname($webtalkServer);
$this = pack($sockaddr, AF_INET, 0, $thisaddr);
$that = pack($sockaddr, AF_INET, $port, $thataddr);
if (!!socket(S, PF_INET, SOCK_STREAM, $proto))
{
$em = "webtalk cgi interface couldn''t create socket";
&quit_with_error;
}
if (!!bind(S, $this))
{
$em = "webtalk cgi interface couldn''t bind socket";
&quit_with_error;
}
if (!!connect(S, $that))
{
$em = "webtalk cgi interface couldn''t connect socket";
&quit_with_error;
}
select(S); $| = 1; select(STDOUT);
######################################################
# send all standard CGI variables to the smalltalk server
######################################################
print S "~GATEWAY_INTERFACE = $ENV{''GATEWAY_INTERFACE''}";
print S "~SERVER_SOFTWARE = $ENV{''SERVER_SOFTWARE''}";
print S "~SERVER_NAME = $ENV{''SERVER_NAME''}";
print S "~SERVER_PROTOCOL = $ENV{''SERVER_PROTOCOL''}";
print S "~SERVER_PORT = $ENV{''SERVER_PORT''}";
print S "~HTTP_USER_AGENT = $ENV{''HTTP_USER_AGENT''}";
print S "~REMOTE_HOST = $ENV{''REMOTE_HOST''}";
print S "~REMOTE_ADDR = $ENV{''REMOTE_ADDR''}";
###################################################
# now handle standard input -
# parse it, and pass the variables to the smalltalk server
###################################################
read(STDIN, $qs, $ENV{"CONTENT_LENGTH"});
&parse_and_send;
###################################################
# now handle the QUERY_STRING environment variable -
# parse it, and pass the variables to the smalltalk server
####################################################
$qs = $ENV{''QUERY_STRING''};
&parse_and_send;
################################################
# now get the smalltalk server''s html page response
# and pass it on
################################################
print S "&";
print "Content-type: text/html\n\n";
while() { print; }
exit 0;
###############################################################
# subroutine to parse qs and print the variables to the socket
################################################################
sub parse_and_send
{
# split it up into an array by the ''&'' character
@array = split(/&/,$qs);
foreach $i (0 .. $#array)
{
# convert the plus chars to spaces
$array[$i] =~ s/\+/ /g;
# convert the wiggle chars to spaces
#$array[$i] =~ s/~/ /g;
# convert the hex tokens to characters
$array[$i] =~ s/%(..)/pack("c",hex($1))/ge;
# split into name and value
($name, $value) = split(/=/,$array[$i],2);
# create the associative element
$array{$name} = $value;
}
foreach $name (sort keys(%array))
{ printf S "~$name = %s", $array{$name} }
}
###############################################################
# subroutine to abort with an error page
################################################################
sub quit_with_error
{
# Send the MIME header
print "Content-type: text/plain\n\n";
print $em;
exit 1;
}'! !
!WebtalkServer class methodsFor: 'documentation' stamp: 'taj 8/19/97 16:29'!
installation
^
'
If you wish for squeak to be your webserver, just type:
WebtalkWebServer startService
and in your browse the address of the machine running Squeak. To stop
it, type:
WebtalkWebServer stopService.
Otherwise, copy the webtalk cgi script into a file called webtalk.pl.cgi and place
it on your webserver with your other CGI scripts (for your convenience,
I have also supplied this file as a separate download). Edit the following
lines near the top of the script:
$hostname = ''webserver.machine'';
$webtalkServer = ''webtalk.machine'';
The first value is the machine the webserver runs on; the second
is the machine that Webtalk will run on.
If you dont currently use any CGI, be sure to configure your webserver
to handle it. I had to add the following to my /etc/httpd.conf:
Exec /cgi/* /usr/web/http/*
Webtalk relies on the VSExceptions, VSEvents, and Connections packages.
Make sure they are installed and working before you try Webtalk.
To start Webtalk, type the following in a workspace:
WebtalkServer startService
(to stop it again, type WebtalkServer stopService)
Go to your browser, and access the following URL:
http://your.server.here/cgi/webtalk.pl.cgi?webtalkClass=MainTestPage
You should see a menu offering a selection of demo applications.
' ! !
!WebtalkServer class methodsFor: 'documentation' stamp: 'taj 8/18/97 05:49'!
license
^
'
Webtalk is (c) 1997 by Thregecy Inc..
Webtalk may be used for any purpose on the Squeak platform,
However, using webtalk on any other Smalltalk system is
not permitted.
' ! !
!WebtalkServer class methodsFor: 'documentation' stamp: 'taj 8/19/97 16:31'!
overview
^'
WHAT IT IS
Webtalk allows one to write interactive web applications using
Squeak.
HOW IT WORKS
Webtalk works either as its own webserver or thru
a CGI - capable web server. The next two paragraphs assume
you are working thru a separate web server.
The web client invokes the Webtalk CGI script on the web server, either
by POSTing or GETing a form, or by explicitly calling it by URL.
The Webtalk CGI script, written in Perl, gathers information from the
systemÕs evironment variables and standard input (provided by the web
server), parses, packages and sends this information to the Smalltalk
image running on another machine using TCP/IP sockets.
The Smalltalk image receives the information, parses it, and
instantiates a subclass of WebtalkPage as determined by the value of the
hidden field webtalkClass passed from the server and embedded originally
in the HTML form or the URL. All of the form data and standard
environment variables can be accessed from this object by using as
selectors the NAME paramter specified for the fields in the HTML file.
The newly created object processes the form information (if any) and
generates a HTML page (using the supplied classes) that is passed back
to the Perl script, and then ultimately to the web client.
State information between screens is maintained by instances of
WebtalkSession. An initial session is created for you which you can
store data in. To make this session information available to other
screens, you must specify the session when creating the form that will
contain the buttons that will lead to another screen. The RPN calculator
application uses sessions.
COMPARISONS TO COMMERCIAL PRODUCTS
I believe this is the same basic capability provide by the IBM and
ParcPlace products, with four major differences:
1.I donÕt generate HTML screens from a GUI painter (which I think is of
dubious value anyway). I do include classes to generate HTML, though.
2.Webtalk costs nothing, as opposed to 1-n thousand dollars
3.Webtalk has not been tested / performance tuned for servers handling
jillions of hits per second.
4.If you have to use Squeak, I donÕt think there is
any other available option (yet). Oh, the joys of monopoly!!!!
WHAT IT WORKS WITH
I imagine one should be able to get this system working on any web
server that supports CGI scripts and Perl, but I have only tested it on
Linux using the CERN 3.0A server. Also, I have only tested the Smalltalk
portion on the Macintosh and Windows versions of Squeak.
'
! !
!WebtalkSession methodsFor: 'private' stamp: 'taj 8/14/97 05:44'!
id
^ id! !
!WebtalkSession methodsFor: 'private' stamp: 'taj 8/19/97 17:05'!
id: i address: a
id _ i.
address := a.
usageCount := 0.
self use.
! !
!WebtalkSession methodsFor: 'private' stamp: 'taj 8/19/97 17:07'!
isAddressOk: a
^address = a ! !
!WebtalkSession methodsFor: 'private' stamp: 'taj 8/18/97 02:42'!
isForsaken
^ (Time now subtractTime: lastAccessTime) asSeconds > self class idleSecondsAllowed! !
!WebtalkSession methodsFor: 'private' stamp: 'taj 8/17/97 13:19'!
release
self class release: self.
self data release.
^super release.! !
!WebtalkSession methodsFor: 'private' stamp: 'taj 8/17/97 13:10'!
use
usageCount := usageCount + 1.
lastAccessTime _ Time now! !
!WebtalkSession methodsFor: 'queries' stamp: 'taj 8/17/97 13:07'!
isNew
^ self usageCount = 1! !
!WebtalkSession methodsFor: 'queries' stamp: 'taj 8/17/97 13:08'!
usageCount
^usageCount! !
!WebtalkSession methodsFor: 'associated data' stamp: 'taj 8/14/97 05:44'!
data
^ data! !
!WebtalkSession methodsFor: 'associated data' stamp: 'taj 8/14/97 05:44'!
data: d
data _ d! !
!WebtalkSession class methodsFor: 'existing instance' stamp: 'taj 8/19/97 17:03'!
id: i address: a
|instance|
self releaseAllForsakenIfEnoughTimeHasPassed.
instance := InstanceDictionary
at: i
ifAbsent: [TimeoutError signal: 'Your session has timed out.'].
(instance isAddressOk: a) ifFalse: [TimeoutError signal: 'Your session has timed out.'].
instance use.
^instance! !
!WebtalkSession class methodsFor: 'initialization' stamp: 'taj 8/17/97 12:59'!
initialize
Id _ 0.
InstanceDictionary _ Dictionary new.
ForsakenKilledAt _ Time now! !
!WebtalkSession class methodsFor: 'instance creation' stamp: 'taj 8/19/97 17:02'!
newForAddress: a
| instance |
self releaseAllForsakenIfEnoughTimeHasPassed.
Id _ Id + 1.
instance _ super new.
instance id: Id address: a.
InstanceDictionary at: Id put: instance.
^ instance ! !
!WebtalkSession class methodsFor: 'forsaken handling' stamp: 'taj 8/17/97 03:39'!
idleSecondsAllowed
^60*5! !
!WebtalkSession class methodsFor: 'forsaken handling' stamp: 'taj 8/17/97 13:15'!
release: i
InstanceDictionary removeKey: i id! !
!WebtalkSession class methodsFor: 'forsaken handling' stamp: 'taj 8/17/97 14:45'!
releaseAllForsaken
(InstanceDictionary select: [:i | i isForsaken]) do: [:i | i release].
ForsakenKilledAt _ Time now ! !
!WebtalkSession class methodsFor: 'forsaken handling' stamp: 'taj 8/17/97 13:16'!
releaseAllForsakenIfEnoughTimeHasPassed
(Time now subtractTime: ForsakenKilledAt ) asSeconds > self idleSecondsAllowed
ifTrue: [self releaseAllForsaken]! !
!WebtalkWebServer methodsFor: 'from StringConnection' stamp: 'taj 10/18/97 03:39'!
eventRead: aString
aString isEmpty
ifTrue: [ self handleRequest: lines. lines := OrderedCollection new ]
ifFalse: [ lines add: aString ].! !
!WebtalkWebServer methodsFor: 'private' stamp: 'taj 10/18/97 05:41'!
basicHandleRequest: requestLines
|request|
request := WebBrowserRequest parse: requestLines.
request isGet ifTrue: [^self handleGet: request].
request isPost ifTrue:
[request postFields: self next.
^self handlePost: request].
self respond: 'this server can only handle get and post requests'.
! !
!WebtalkWebServer methodsFor: 'private' stamp: 'taj 10/18/97 07:15'!
handleFileRequest: request
|filename directoryCharacter url|
url := request url.
self log add: request description,' ',self remoteAddress.
url := url copyFrom: 2 to: url size.
directoryCharacter := FileDirectory activeDirectoryClass pathNameDelimiter.
filename := self class baseDirectory,url.
filename := filename collect: [:c| c = $/ ifTrue:[directoryCharacter] ifFalse:[c]].
self respond:
((FileStream concreteStream isAFileNamed: filename)
ifTrue: [(FileStream fileNamed: filename) contentsOfEntireFile]
ifFalse: [url,' not found'])
! !
!WebtalkWebServer methodsFor: 'private' stamp: 'taj 10/18/97 06:31'!
handleGet: request
|url|
url := request url.
url = '/' ifTrue:
[request addField: 'webtalkClass=',WebtalkPage default printString.
^self handleWebtalkRequest: request].
(url includes: $?)
ifTrue: [self handlePost: request]
ifFalse: [self handleFileRequest: request]
! !
!WebtalkWebServer methodsFor: 'private' stamp: 'taj 10/18/97 05:08'!
handlePost: request
"right now, only webtalk requests are processed"
self handleWebtalkRequest: request. ! !
!WebtalkWebServer methodsFor: 'private' stamp: 'taj 10/18/97 06:34'!
handleRequest: requestLines
[self basicHandleRequest: requestLines] on: Error do: [:x| self respond: x description]
! !
!WebtalkWebServer methodsFor: 'private' stamp: 'taj 10/18/97 04:27'!
handleWebtalkRequest: request
|dictionary|
dictionary := Dictionary new.
dictionary at: 'GATEWAY_INTERFACE' put: 'Webtalk Web Server Interface'.
dictionary at: 'SERVER_SOFTWARE' put: 'Webtalk Web Server'.
dictionary at: 'SERVER_NAME' put: Connection localAddress.
dictionary at: 'SERVER_PROTOCOL' put: 'HTTP/1.0'.
dictionary at: 'SERVER_PORT' put: 'unknown'.
dictionary at: 'HTTP_USER_AGENT' put: (request headerFieldValue: 'User-Agent').
dictionary at: 'REMOTE_HOST' put: self remoteAddress.
dictionary at: 'REMOTE_ADDR' put: self remoteAddress.
request fields associationsDo: [:a| dictionary at: a key put: a value].
self respond: (WebtalkPage process: dictionary log: self log).
! !
!WebtalkWebServer methodsFor: 'private' stamp: 'taj 10/18/97 05:14'!
log
log isNil ifTrue: [log _ Log to: self class logFilename].
^ log ! !
!WebtalkWebServer methodsFor: 'private' stamp: 'taj 10/18/97 06:33'!
respond: aString
self isClosed
ifFalse: [self nextPut: aString. self close]
ifTrue: [Transcript show: 'connection closed, could not respond: ',aString;cr]! !
!WebtalkWebServer methodsFor: 'initialization' stamp: 'taj 8/19/97 12:03'!
initialize
super initialize.
lines := OrderedCollection new.
! !
!WebtalkWebServer class methodsFor: 'configuration' stamp: 'taj 10/18/97 05:18'!
baseDirectory
^''! !
!WebtalkWebServer class methodsFor: 'configuration' stamp: 'taj 10/17/97 07:53'!
listeningPortsCount
^5! !
!WebtalkWebServer class methodsFor: 'configuration' stamp: 'taj 10/18/97 05:13'!
logFilename
^'log.txt'! !
!WebtalkWebServer class methodsFor: 'configuration' stamp: 'taj 8/19/97 15:10'!
startService
^self service: 80! !
HTMLPage initialize!
WebtalkSession initialize!