You are viewing a plain text version of this content. The canonical link for it is here.
Posted to site-cvs@tcl.apache.org by da...@apache.org on 2002/05/08 12:31:15 UTC
cvs commit: tcl-site/websh/titles strich1.gif strich2.gif t_neutral.gif t_neutral2.gif t_product.gif
davidw 02/05/08 03:31:14
Added: websh #index.ws3# Makefile bugsubmit buttons.js
checkbox.sample contact.ws3 cookie.sample
copyright.ws3 dispatch_1.sample docu.ws3
download.ws3 emailform.sample error.ws3
examples.pre examples.syp examples.ws3 faq.syp
faq.ws3 helloworld.sample image.sample index.ws3
install.tcl memory.sample privacy.ws3 product.ws3
quickref.syp quickref.ws3 quickref.xml
quickref_head.txt quickref_pdf_head.html
resources.ws3 session_form.sample subscribe.ws3
support.ws3 syp.tcl syp2txt.tcl tutorial.syp
tutorial.ws3 unsubscribe.ws3 upload.sample
websh.com.gen websh.css whitepaper.syp
whitepaper.ws3 whitepaper_head.txt
whitepaper_pdf_head.html ws32html.ws3
websh/buttons b_abschluss.gif b_docu_a.gif b_docu_b.gif
b_docu_c.gif b_down_a.gif b_down_b.gif b_down_c.gif
b_prod_a.gif b_prod_b.gif b_prod_c.gif b_ress_a.gif
b_ress_b.gif b_ress_c.gif b_supp_a.gif b_supp_b.gif
b_supp_c.gif pfeile.gif
websh/images ausschnitt_download.gif ausschnitt_product.gif
ausschnitt_ressources.gif ausschnitt_support.gif
b_ress_a.gif b_ress_b.gif b_ress_c.gif bg.gif
drei.gif drei_klein.gif element1_navi.gif
element2_navi.gif empty.gif grafik_index.gif
grafik_navi.gif grafik_navi_home.gif
grafik_strich_unten.gif grafik_strich_unten2.gif
headline.gif headline2.gif logo.gif logo_strich.gif
logo_strich2.gif pfeil.gif punkt_grau.gif
punkt_rot.gif stuntFFFFFF001010.gif uppfeil.gif
ws3arch.gif ws3ov.gif
websh/talks/ncaintro Makefile bg.gif classes.gif
config_file.sample cookie.sample dispatch.sample
embed.sample encrypt.sample filecontext.sample
filters.gif form.sample helloworld.sample
history.gif httpd.conf.sample idflow.gif
lifetime.gif logging.sample logging2.sample
mod_websh_cfg.tcl.sample ncaintro.syp runsample.ws3
samples.css states.gif stunt.gif template.html
transactions.gif weblog.gif ws3arch.gif ws3ov.gif
wsp.sample wsp.tcl.sample wsphandler.sample
websh/titles strich1.gif strich2.gif t_neutral.gif
t_neutral2.gif t_product.gif
Log:
Commited websh site to tcl-site repository. Further work necessary
before releasing - files need to be cleaned up: remove/change
references to Netcetera, change webshell to Websh, and so forth.
Revision Changes Path
1.1 tcl-site/websh/#index.ws3#
Index: #index.ws3#
===================================================================
## www.websh.com/index.html
## nca-115-2
## $Id: #index.ws3#,v 1.1 2002/05/08 10:31:09 davidw Exp $
#web::response -sendheader 0
# source [file join [file dirname [web::request SCRIPT_FILENAME]] websh.com.gen]
startHtmlPage
startHtmlBody
putHeader 0 0
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
<tr height="30">
<td width="300" rowspan="2" valign="top"><img height="380" width="300" src="images/headline.gif" alt="Headline"></td>
<td width="315" height="30"><h1>Welcome</h1></td>
<td width="10" rowspan="2"></td>
<td width="140" height="30"><h1>News</h1>
</td>
</tr>
<tr valign="top">
<td width="315"><img height="160" width="120" src="images/drei_klein.gif" align="left">
The Internet is growing rapidly. Daily you find new
applications and new home-pages - new opportunities for
success and profit. The basic technologies behind the
Internet, however, have remained stable for years. Only on
a solid basis can you build new stuff.<br>
<br>
<!-- Since 1996, Netcetera's success has been based on webshell.
This rapid development environment for building powerful web
applications is rock solid, but by no means a monolith: the
webshell rather is the glue to assemble complex
applications. Netcetera continues this traditionally
innovative concept with webshell 3.<br>
<br>
-->
</td>
<td width="140">
<table border="0" cellpadding="0" cellspacing="0" width="145">
{newsBarElement "Newsletter" \
{<FORM action="/bin/mail/websh_news?cmd=subscribe" method="POST">
<INPUT TYPE="TEXT" SIZE="10" MAXLENGTH="35" NAME="user">
<INPUT type="submit" value="join">
</FORM>
}
}
{newsBarElement "websh 3.0.0 available:" \
{pick the {pageLink /downloaddir/websh-3.0.0.tar.gz -show "tarball"}
or browse the {pageLink /download.html -show "download area"}.
}
}
{newsBarElement "Examples" \
{ Check out the<br> {pageLink /examples.html -show "live examples"}<br>
of Webshell applications.
}
}
</table>
<br>
</td>
</tr>
</table>
}
finishPage
1.1 tcl-site/websh/Makefile
Index: Makefile
===================================================================
# Makefile -- preliminary make file
# nca-115-2
#
# (c) 1999 netcetera AG (simon.hefti@netcetera.ch)
#
# $Id: Makefile,v 1.1 2002/05/08 10:31:09 davidw Exp $
.SUFFIXES: .ws3 .html .syp .pre .sample
WEBSH3 = websh3
WEBHOME = /wwwdev/websh
sources := contact.ws3 \
copyright.ws3 \
docu.ws3 \
download.ws3 \
error.ws3 \
examples.ws3 \
index.ws3 \
privacy.ws3 \
product.ws3 \
quickref.ws3 \
ressources.ws3 \
subscribe.ws3 \
support.ws3 faq.ws3 \
tutorial.ws3 \
unsubscribe.ws3 \
whitepaper.ws3
examples := helloworld.sample \
dispatch_1.sample \
session_form.sample \
memory.sample \
cookie.sample \
image.sample \
emailform.sample \
upload.sample
examples_html := $(examples:.sample=.html)
examples_exe := $(examples:.sample=)
objects := $(sources:.ws3=.html)
talk_ncaintro := $(wildcard talks/ncaintro/*.html) \
talks/ncaintro/bg.gif \
talks/ncaintro/ws3arch.gif \
talks/ncaintro/ws3ov.gif \
talks/ncaintro/weblog.gif \
talks/ncaintro/classes.gif \
talks/ncaintro/lifetime.gif \
talks/ncaintro/filters.gif \
talks/ncaintro/stunt.gif \
talks/ncaintro/transactions.gif \
talks/ncaintro/idflow.gif \
all: $(objects) websh.com.gen
@echo == main. Target: all ==
## make sure example code is up-to-date
# websh3 fontifyws3.tcl /wwwdev/websh/cgi-bin/examples/helloworld > \
# /wwwdev/websh/docs/helloworld.html; \
# chmod ugo-rwxst,ugo+r,u+w /wwwdev/websh/docs/helloworld.html
# websh3 fontifyws3.tcl /wwwdev/websh/cgi-bin/examples/dispatch_1 > \
# /wwwdev/websh/docs/dispatch_1.html; \
# chmod ugo-rwxst,ugo+r,u+w /wwwdev/websh/docs/dispatch_1.html
# cat /wwwdev/websh/bugdb/bin/wrapper /wwwdev/websh/bugdb/lib/sdb.ws3 > tmp_code; \
# websh3 fontifyws3.tcl tmp_code > /wwwdev/websh/docs/bugdb.html; \
# chmod ugo-rwxst,ugo+r,u+w /wwwdev/websh/docs/bugdb.html
samples: $(examples_html)
@echo == main. Target: samples ==
@echo $(examples_html)
pdf: quickref.syp quickref_pdf_head.html whitepaper.syp whitepaper_pdf_head.html
$(WEBSH3) syp.tcl quickref.syp tmp
cat quickref_pdf_head.html tmp > quickref_pdf.html
$(WEBSH3) syp.tcl whitepaper.syp tmp
cat whitepaper_pdf_head.html tmp > whitepaper_pdf.html
txt: quickref.syp whitepaper.syp
$(WEBSH3) syp.tcl quickref.syp -tr syp2txt.tcl tmp
cat quickref_head.txt tmp > websh30b2-quickref.txt
$(WEBSH3) syp.tcl whitepaper.syp -tr syp2txt.tcl tmp
cat whitepaper_head.txt tmp > websh30b2-whitepaper.txt
install:
@install.tcl websh.com.gen $(WEBHOME)/lib/websh.com.gen ugo+r
@install.tcl bugsubmit $(WEBHOME)/cgi-bin/bugsubmit ugo+rx
@for i in $(objects) websh.css buttons.js; \
do \
install.tcl $$i $(WEBHOME)/docs/$$i ugo+r; \
done
## examples: txt doc
@for i in websh30b2-whitepaper.* websh30b2-quickref.* ; \
do \
install.tcl $$i $(WEBHOME)/docs/downloaddir/$$i ugo+r; \
done
## examples: html
@for i in $(examples_html); \
do \
install.tcl $$i $(WEBHOME)/docs/examples/$$i ugo+r; \
done
## examples: code
@for i in $(examples_exe); \
do \
install.tcl $$i.sample $(WEBHOME)/cgi-bin/examples/$$i ugo+rx; \
install.tcl $$i.sample $(WEBHOME)/docs/examples/$$i.ws3 ugo+r; \
done
## images
@for i in images/*.* titles/*.* buttons/*.*; \
do \
install.tcl $$i $(WEBHOME)/docs/$$i ugo+r; \
done
## talks: ncaintro
@for i in $(talk_ncaintro); \
do \
install.tcl $$i $(WEBHOME)/docs/$$i ugo+r; \
done
clean:
@echo == main. Target: clean ==
rm -f $(objects) $(examples_html)
rm -f faq.pre whitepaper.pre tutorial.pre quickref.pre
rm -f tmp quickref.txt whitepaper.txt quickref_pdf.html
rm -f tmp quickref_pdf.html whitepaper_pdf.html
faq.ws3: faq.pre
faq.pre: faq.syp
whitepaper.ws3: whitepaper.pre
whitepaper.pre: whitepaper.syp
#tutorial.ws3: tutorial.pre
#tutorial.pre: tutorial.syp
quickref.ws3: quickref.pre
quickref.pre: quickref.syp
examples.ws3: examples.pre
examples.pre: examples.syp
.ws3.html: websh.com.gen
@echo " == Building $@ =="
websh3 $< > $@
.syp.pre: websh.com.gen
@echo " == Building $@ =="
$(WEBSH3) syp.tcl $< $@
.sample.html:
@echo " == Building $@ =="
$(WEBSH3) ws32html.ws3 $< > $@
#helloworld.html: helloworld.sample
#dispatch_1.html: dispatch_1.sample
#session_form.html: session_form.sample
1.1 tcl-site/websh/bugsubmit
Index: bugsubmit
===================================================================
#! ../bin/websh3
web::logfilter add *.-debug
web::logdest add *.-debug file "../logs/bugsubmit.log"
source ../lib/websh.com.gen
proc page {nr code} {
startHtmlPage
startHtmlBody
putHeader $nr
uplevel $code
finishPage $nr
}
proc form {page code} {
page 3 {
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 4 "Bug submission form"}
<tr valign="top">
{navbar_supp 3}
<td width="455">
{
web::put "<form method=\"POST\" action=\"[web::cmdurl $page]\">"
uplevel $code
web::put "</form>"
}
</td>
{newsbar_supp}
</tr>
</table>
}
}
}
proc putErrorMessage {msg} {
# emit an error message in red.
web::put "<p><font color=\"\#ff0000\">[web::htmlify $msg]</font></p>"
}
# confirmation page
proc confirm {} {
page 3 {
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 4 "Bug submission form"}
<tr valign="top">
{navbar_supp 1}
<td width="455">
{
web::put "<h3>thank you</h3>\n"
web::put "Your submission:<br>\n"
web::put "<b>Short Description:</b><br>\n"
web::put "[web::htmlify -- [web::formvar sdsc]]<br>\n"
#
web::put "<b>webshell version:</b>\n"
web::put "[web::htmlify -- [web::formvar webshver]]<br>\n"
#
web::put "<b>Severity:</b><br>\n"
web::put "[web::htmlify -- [web::formvar severity]]<br>\n"
#
web::put "<b>Description:</b><br>\n"
web::put "[web::htmlify -- [web::formvar ldsc]]<br>\n"
#
if {[string length [web::formvar email]] > 1} {
web::put "<b>e-mail:</b><br>\n"
web::put "[web::htmlify -- [web::formvar email]]<br>\n"
}
web::put "has been forwarded to our websh experts."
}
</td>
{newsbar_supp}
</tr>
</table>
}
}
}
proc emailify {list} {
foreach item $list {
append res [xmlify $item]
}
return $res
}
proc xmlify {varName} {
set res "<$varName>"
if {[string length [web::formvar $varName]] > 1} {
append res "[web::formvar $varName]\n"
}
append res "</$varName>\n"
return $res
}
# process submission
web::command doSubmit {
if { [string length [web::formvar sdsc]] < 1 } {
submit "Please enter a short description."
} elseif { [string length [web::formvar webshver]] < 1 } {
submit "Please enter the webshell version."
} elseif { [string length [web::formvar email]] > 1 } {
if { ![check_email [web::formvar email] ] } {
submit "Please enter a valid e-mail address (if any)."
}
}
# send by e-mail
set fh [open "| /usr/lib/sendmail support@websh.com" w]
if { [string length [web::formvar email]] > 1 } {
puts $fh "From: [web::formvar email]"
}
puts $fh "Subject: \[ws3-bug\] [web::formvar sdsc]"
puts $fh ""
set tmp [emailify [list sdsc webshver severity ldsc email]]
puts $fh $tmp
close $fh
web::log info $tmp
confirm
}
# check_email
proc check_email {address} {
return [regexp "\[^ \.\]+@\[^ \t\]+\\\.\[^ \t\]+$" $address]
}
# input -- format the "submit" button
proc input {type name size value} {
set res "<input type=\"$type\" name=\"$name\" size=\"$size\" "
append res "value=\"$value\">\n"
return $res
}
# textarea
proc textarea {rows cols name value} {
set res "<textarea rows=\"$rows\" cols=\"$cols\" name=\"$name\">"
append res $value
append res "</textarea>\n"
return $res
}
# select -- ooutput HTML combobox
proc select {name list selected} {
set res "<select name=\"$name\">\n"
foreach option $list {
if {$option == $selected} {
append res "<option selected>$option\n"
} else {
append res "<option>$option\n"
}
}
append res "\n</select>\n"
return $res
}
# show bug submission form
proc submit {{errorMessage ""}} {
form doSubmit {
if {[string length $errorMessage]} {
putErrorMessage $errorMessage
}
web::put "<b>Short Description:</b><br>\n"
web::put "[input text sdsc 45 [web::formvar sdsc]]<br>\n"
#
web::put "<b>webshell version:</b> (use web::copyright -version)\n"
web::put "[input text webshver 45 [web::formvar webshver]]<br>\n"
#
web::put "<b>Severity:</b><br>\n"
web::put "[select severity [list suggestion glitch bug fatal] [web::formvar severity]]<br>\n"
#
web::put "<b>Description:</b><br>\n"
web::put "[textarea 10 45 ldsc [web::formvar ldsc]]<br>\n"
#
web::put "If you would like to be notified when this bug is "
web::put "fixed, you can add your e-mail:<br>"
web::put "<b>e-mail:</b> (optional)<br>\n"
web::put "[input text email 45 [web::formvar email]]<br>\n"
#
web::put "<input type=\"submit\" value=\"submit\">"
web::put "<input type=\"reset\" value=\"reset\">"
}
}
web::command default {
submit
}
web::dispatch
1.1 tcl-site/websh/buttons.js
Index: buttons.js
===================================================================
if (document.images) {
var prod_a = new Image();
var prod_b = new Image();
var docu_a = new Image();
var docu_b = new Image();
var supp_a = new Image();
var supp_b = new Image();
var ress_a = new Image();
var ress_b = new Image();
var down_a = new Image();
var down_b = new Image();
prod_a.src ="buttons/b_prod_a.gif";
prod_b.src ="buttons/b_prod_b.gif";
docu_a.src ="buttons/b_docu_a.gif";
docu_b.src ="buttons/b_docu_b.gif";
supp_a.src ="buttons/b_supp_a.gif";
supp_b.src ="buttons/b_supp_b.gif";
ress_a.src ="buttons/b_ress_a.gif";
ress_b.src ="buttons/b_ress_b.gif";
down_a.src ="buttons/b_down_a.gif";
down_b.src ="buttons/b_down_b.gif";
}
function wechsel(bild,kennung) {
if(document.images) {
document[bild].src = "buttons/" + kennung + ".gif";
}
}
1.1 tcl-site/websh/checkbox.sample
Index: checkbox.sample
===================================================================
#! ../../bin/websh3
#
# This Example shows you how to handle checkboxes in a form.
#
# set flag
set first_load "on"
# see confirmation form example
proc page {title code} {
web::putx {<html><head><title>{web::put $title}</title></head>
<body bgcolor="#ffffff" text="#000000">
<h3>{web::put $title}</h3>
}
uplevel $code
web::put "</body></html>\n"
}
# see confirmation form example
proc form {page code} {
web::put "<form enctype=\"text/html\" method=\"post\" action=\"[web::cmdurl $page]\">"
uplevel $code
web::put "</form>"
}
proc showForm {error} {
global first_load
# generate a page with Title "File upload example"
page "checkbox example" {
# generate a form with action "submit"
# the return value of a checkbox is no value or "on"
form "submit" {
# web::match is used to search the value "on" in the variables time_flag and firstload.
# If the value is found it returns a checked.
web::putx {
<br>Please choose the information that should be displayed.<br><br>
Time
<input name="time_flag" type="checkbox" {web::put [web::match "checked" [web::formvar time_flag $first_load] "on"]}>
Day
<input name="day_flag" type="checkbox" {web::put [web::match "checked" [web::formvar day_flag $first_load] "on"]}>
Date
<input name="date_flag" type="checkbox" {web::put [web::match "checked" [web::formvar date_flag $first_load] "on"]}>
<br>
{set output [web::match "%T " [web::formvar time_flag $first_load] "on"]}
{append output [web::match "%A " [web::formvar day_flag $first_load] "on"]}
{append output [web::match "%d.%m.%Y" [web::formvar date_flag $first_load] "on"]}
{web::put [clock format [clock seconds] -format $output]}
<br>
<input type="submit" name="ok" value="Send">
}
}
}
}
# see confirmation form example
web::command default {
showForm 0
}
# With the set first_load 0 we know that the showForm is not displayed
# the first time.
# See also confirmation form example.
web::command submit {
set first_load 0
showForm 0
}
#see dispatch example
web::dispatch
1.1 tcl-site/websh/contact.ws3
Index: contact.ws3
===================================================================
## www.websh.com/contact.html
## nca-115-2
## $Id: contact.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 0
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 2 "contact"}
<tr valign="top">
{navbar_null}
<td width="300">
WebSH is a product of the Apache Software Foundation's <a href="http://tcl.apache.org/">Apache Tcl</a> group.<br>
To contact the WebSH developers, send email <a href="mailto:websh-dev@tcl.apache.org">websh-dev@tcl.apache.org</a>.
</td>
</tr>
</table>
}
finishPage
1.1 tcl-site/websh/cookie.sample
Index: cookie.sample
===================================================================
#! ../../bin/websh3
# cookie example - store context in a cookie
#
# this example demonstrates how to use cookies with websh3
#
# create session context manager with the name "state"
web::cookiecontext state
# produce the page of this sample application
proc page {} {
# get current access counter from state ...
set cnt [state::cget cnt 0]
# ... and increment right away
#
# Note: cookie must be sent before the first "web::put" is used
# This is because a cookie must be sent as a HTTP header
set newcnt $cnt
incr newcnt
state::cset cnt $newcnt
# commit the changes on the state
state::commit
# now the html output
web::put "<html><head><title>Cookie Example</title></head>"
web::put "<body bgcolor=\"#FFFFFF\">"
# change welcome text depending on state
if { $cnt == 0 } {
# the first time a warm welcome
web::put "<h1>Welcome</h1>"
web::put "to the wonderful world of Websh"
} else {
# then just a hello
web::put "<h1>Hello</h1>"
web::put "looks like this is your visit Nr $cnt"
}
web::put "<p>"
# and give the user the change to:
# - invalidate the cookie
web::put "<a href=\"[web::cmdurl clearCookie]\">reset</a>"
web::put " | "
# - to move on to the next page of the application
# in this example, just go back to the same page
web::put "<a href=\"[web::cmdurl default]\">next visit</a>"
# properly close html code
web::put "</body></html>"
}
web::command clearCookie {
# get current cookie, if any
state::init mycookie
# ... and invalidate immediately
state::invalidate
# show page
page
}
web::command default {
# get current cookie, if any
state::init mycookie
# show page
page
}
# dispatch
web::dispatch
1.1 tcl-site/websh/copyright.ws3
Index: copyright.ws3
===================================================================
## www.websh.com/copyright.html
## nca-115-2
## $Id: copyright.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 0
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 3 "Copyright Notice"}
<tr valign="top">
{navbar_null}
<td width="455">
Copyright © 2000 by Netcetera AG.<br>
Copyright © 2001, 2002 by the Apache Software Foundation.<br>
All rights reserved.<br>
<br>
We try to keep this page up-to-date and hope that
it will be useful. We do not guarantee that it is suitable for any
particular purpose whatsoever. The authors accept no liability in
respect to this information or its use.
<br><br><br>
Thank you for your interest in webshell.
</td>
</tr>
</table>
}
finishPage
1.1 tcl-site/websh/dispatch_1.sample
Index: dispatch_1.sample
===================================================================
#! ../../bin/websh3
# register the websh command "pricelist"
web::command pricelist {
# web::put sends string to the default output channel
# (stdout in the CGI case), including HTTP headers
web::put {<tt><h2>price list</h2></tt>}
# web::cmdurl produces a URL with querystring. In this case,
# we just want to switch back to "default", that's why we omit
# an explicit command name and just use ""
web::put "<a href=\"[web::cmdurl ""]\">back</a>"
}
# register the websh command "default"
web::command default {
# welcome note
web::put {<tt><h2>hello, customer</h2></tt>}
# link to an other HTML page of this application, the price list.
# We generate the URL using web::cmdurl and specify the command
# to be used: it is called pricelist and has been defined above.
web::put "<a href=\"[web::cmdurl pricelist]\">price list</a>"
}
# do the command dispatching
# this will switch into "pricelist" or "default" depending on
# the query_string
web::dispatch
1.1 tcl-site/websh/docu.ws3
Index: docu.ws3
===================================================================
## www.websh.com/docu.html
## nca-115-2
## $Id: docu.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 2
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 3 "documentation"}
<tr valign="top">
{navbar_docu}
<td width="610">
This is your one-stop shop for all webshell documentation.
<h2>White Paper</h2>
The white paper outlines how webshell is used, describes
its architecture, and explains design decisions.<br>
<a href="whitepaper.ws3">html</a> |
<a href="downloaddir/websh30a2-whitepaper.pdf">pdf</a> |
<a href="downloaddir/websh30b2-whitepaper.txt">text</a><br>
<h2>Quick Reference</h2>
Know how to use webshell, but keep forgetting the
syntax ? The quick reference has everything you need to
know.<br>
<a href="quickref.html">html</a> |
<a href="downloaddir/websh30b1-quickref.pdf">pdf</a> |
<a href="downloaddir/websh30b2-quickref.txt">txt</a>
<h2>Code Examples</h2>
The <a href="examples.html">example</a> page demonstates
webshell features - you can both look at the code and play
with the application.
<h2 class="grey">Reference</h2>
Also, we are compiling the webshell reference, a thorough
technical documentation of webshell.
</td>
</tr>
</table>
}
finishPage 2
1.1 tcl-site/websh/download.ws3
Index: download.ws3
===================================================================
## www.websh.com/download.html
## nca-115-2
## $Id: download.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 5
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 3 "download"}
<tr valign="top">
{navbar_down 0}
<td width="610">
<img height="160" width="270" src="images/ausschnitt_download.gif" align="left" alt="graphics">
We have source and binaries available for download:
<DL>
<DT>{pageLink /downloaddir/websh-3.0.0.tar.gz -show "websh-3.0.0.tar.gz"}
<DD>new: 3.0 release (204kB)
<DT>{pageLink /downloaddir/websh-3.0.0.tgz -show "websh-3.0.0.tgz"}
<DD>FreeBSD package of websh 3.0.0 (121kB)
<DT>{pageLink /downloaddir/websh3.tar.gz -show " websh3.tar.gz"}
<DD>FreeBSD port of websh 3.0.0 (2kB)
<DT>{pageLink /downloaddir/websh-3.0b2-1.i386.rpm -show "websh-3.0b2-1.i386.rpm"}
<DD>rpm for beta-2 (121kB)<br>
This Red Hat Package file requires Tcl 8.2 or higher to be installed
on your Linux system (for your convenience, we have the Tcl 8.2.2
rpm available {pageLink /downloaddir/tcl-8.2.2-2.rh6.1.i386.rpm -show "here"}).
<DT>
<DD>
<DT>{pageLink /downloaddir/websh-3.0b1.zip -show "websh-3.0b1.zip"}
<DD>Windows/NT binary (1MB)
</DL>
<br><br>
If you would like to be notified when new versions of webshell
become available for download, you can subscribe to the webshell
newsletter at {pageLink /subscribe.html -show "http://websh.com/subscribe.html"}.
</td>
</tr>
</table>
}
finishPage 5
1.1 tcl-site/websh/emailform.sample
Index: emailform.sample
===================================================================
#! ../../bin/websh3
# "order" form example
#
# The "customer" fills out a form, say an order form.
# The form data is validated and a confirmation page
# displayed. ALso, a confirmation e-mail is sent to the
# customer.
#
# In addition, logging is used.
# turn on logging
#
# web::logfilter determines which log messages will be sent to the log
# destination. The rule here is: let all log messages pass which have
# facilities that match "*" and which have a level up to and including
# level "debug"
web::logfilter add *.-debug
# define where to send log messages to. Here we use a file
# and again define a log destination based filter, which is again
# "*.-debug" as above
web::logdest add *.-debug file ../../logs/emailform.log
# utility command to handle an HTML page
proc page {title code} {
web::putx {<html><head><title>{web::put $title}</title></head>
<body bgcolor="#ffffff" text="#000000">
<h1>{web::put $title}</h1>
}
uplevel $code
web::put "</body></html>\n"
}
# utility command to handle an html form
proc form {page code} {
web::put "<form method=\"post\" action=\"[web::cmdurl $page]\">"
uplevel $code
web::put "</form>"
}
# define the form where address is entered
proc showForm {error} {
# generate a page with Title "Form"
page "Order Form" {
# generate a form with action "submit"
form "submit" {
web::putx {
<dl>
<dt><b>Name:</b> {
# if "error" flag is set, show the red error message asking for input
if {$error == 1} {
web::put "<font color=\"\#990000\">Please enter your name</font>\n"
}
}
<dd><input type="text" name="name" value="{web::put [web::htmlify [web::formvar name]]}" size="30"><p>
<dt><b>Address:</b>
<dd><textarea name="addr" rows="4" cols="30" wrap="auto">{web::put [web::htmlify [web::formvar addr]]}</textarea><p>
<dt><b>E-Mail:</b> {
# if "error" flag is set, ask for valid e-mail address
if {$error == 2} {
web::put "<font color=\"\#990000\">Please enter a valid email addres</font>\n"
}
}
<dd><input type="text" name="email" value="{web::put [web::htmlify [web::formvar email]]}" size="30"><p>
</dl>
<input type="submit" name="ok" value="Send">
}
}
}
}
# validator:
#
# make sure we have a name of non-zero length.
# Also, make sure the e-mail address is not completely wrong.
proc checkFormData {} {
# check if a value is in the name field
if { [string length [web::formvar name]] < 1} {
# return error code
return 1
}
# log (facility: emailform, level: debug)
web::log emailform.debug {name [web::formvar name] is valid}
# check email
set email [web::formvar email]
# make sure we have alpha-numeric stuff separated by "@"
if {![regexp -nocase {^([a-z0-9]+)@([a-z0-9]+)\.+([a-z]+)$} \
$email email name domain]} {
# return error code
return 2
}
# check length of domain
if {[string length $domain] < 3} {
return 2
}
web::log emailform.debug {email [web::formvar email] is valid}
# looks good: no error
return 0
}
# sendEmail
#
# create the e-mail message and send it to the given e-mail address
proc sendEmail {} {
set emailtxt {
Thank you for your submission.
We have recieved the following information:}
append emailtxt "\nName:\n[web::formvar name]\n"
append emailtxt "Address:\n"
append emailtxt [web::formvar addr]
append emailtxt {
Find more information about Webshell at http://websh.com
The team.
}
# log message
web::log emailform.debug "e-mail: $emailtxt"
if { [catch {
# Open pipe for e-mail
set fh [open "| /usr/lib/sendmail [web::formvar email]" w]
puts $fh "From: info@websh.com"
puts $fh "Subject: websh3 sample application - sample confirmation"
puts $fh ""
puts $fh $emailtxt
close $fh
} cmsg ] } {
showErrorPage
}
}
proc showErrorPage {} {
page "Error" {
web::putx {
<h3>Error</h3>
An error occurred while processing your request.
Please {web::put <a href=\"[web::cmdurl default]\">try</a>} again
<br><br>
If the problem persists, please contact the
{web::put <a href=\"mailto:webmaster@tcl.apache.org\">webmaster</a>}.
}
}
}
proc showConfirmationPage {} {
page "Confirmation" {
web::putx {
<h3>Thank you for your order</h3>
We have recieved the following information:
<dl>
<dt><b>Name:</b>
<dd>{web::put [web::htmlify [web::formvar name]]}<p>
<dt><b>Address:</b>
<dd>{
# take care of linebreaks in address
regsub -all "\r\n" [web::htmlify [web::formvar addr]] "<br>" addr
web::put $addr
}<p>
<dt><b>E-Mail:</b>
<dd>{web::put [web::htmlify [web::formvar email]]}<p>
</dl>
You should recieve a confirmation by e-mail shortly.
<br>
{web::put <a href=\"[web::cmdurl default]\">Order more</a>}
cool stuff.
}
}
}
# register the "default" command
#
# This command will be used whenever no specific command has been specified.
# We use it to show an empty form for address submission.
web::command default {
showForm 0
}
# register command "submit"
#
# This is the "action" of our form. The form data is validated. If
# the formdata is incomplete or invalid, the form is re-displayed with
# an error info, where the original input is displayed as well.
#
# If the data is valid, the confirmation page is shown and
# an e-mail is sent to the specified address.
web::command submit {
if { [set res [checkFormData]] == 0 } {
sendEmail
showConfirmationPage
} else {
showForm $res
}
}
web::dispatch
1.1 tcl-site/websh/error.ws3
Index: error.ws3
===================================================================
## www.websh.com/contact.html
## nca-115-2
## $Id: error.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 0
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 2 "Invalid Page"}
<tr valign="top">
{navbar_null}
<td width="300">
You selected an invalid page.
</td>
</tr>
</table>
}
finishPage
1.1 tcl-site/websh/examples.pre
Index: examples.pre
===================================================================
This section presents a selection of sample webshell applications.
All applications are described in detail on this page and come with
richly documented source code. For simplicity, they are all-in-one
files. Plus, they are on-line and ready to use. For each application
discussed below, you will find the corresponding links which present
the code and the live application. Both links will open a new browser
window. You can therefore easily browse through the examples, and look
at the code and the live example simultaneously.
<br>
<a name="toc"><a href="#toc"><h1>1 Table of Contents</h1></a>
<br>1 <a href="#toc"><b>Table of Contents</b></a><br>
<br>2 <a href="#13"><b>hello world</b></a><br>
<br>3 <a href="#26"><b>command dispatching</b></a><br>
<br>4 <a href="#41"><b>image</b></a><br>
<br>5 <a href="#51"><b>confirmation form</b></a><br>
<br>6 <a href="#62"><b>checkbox form</b></a><br>
<br>7 <a href="#72"><b>upload file</b></a><br>
<br>8 <a href="#83"><b>sessions</b></a><br>
<br>9 <a href="#103"><b>cookie</b></a><br>
<br>10 <a href="#111"><b>memory game</b></a><br>
<br><br>
<a name="13"><a href="#toc"><h1>2 hello world</h1></a>
In order to get a first impression, let's look at a simple example.
All it does is printing "Hello, world". It consists of one websh
command, <tt>web::put</tt>. Basically, <tt>web::put</tt> works like Tcl's
<tt>puts</tt> command. In addition to printing the text, it does send HTTP
headers when invoked for the first time.<br>
<a href="/examples/helloworld.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
<a href="/bin/examples/helloworld" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
<a href="/examples/helloworld.ws3">download</a>
<a name="26"><a href="#toc"><h1>3 command dispatching</h1></a>
Now, let's look at one of the main features of websh: the command
dispatching. This allows you to produce all your HTML page from one
and the same source code. This example produces two HTML pages, the
"greetings" page and a "price list" page (even though, for simplicity,
the price list is empty). It uses <tt>web::dispatch</tt> to switch into one
of these pages, and <tt>web::cmdurl</tt> to produce URLs pointing to each
of these pages.<br>
<a href="/examples/dispatch_1.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
<a href="/bin/examples/dispatch_1" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
<a href="/examples/dispatch_1.ws3">download</a>
<a name="41"><a href="#toc"><h1>4 image</h1></a>
This example demonstrates how to return an image instead of the
normal "text/html" mime type.<br>
<a href="/examples/image.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
<a href="/bin/examples/image" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
<a href="/examples/image.ws3">download</a>
<a name="51"><a href="#toc"><h1>5 confirmation form</h1></a>
This example demonstrates a confirmation form. The user is promted a form to
enter, say, order information. The information is validated and, if sucessfull,
an e-mail is sent back to the user.<br>
<a href="/examples/emailform.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
<a href="/bin/examples/emailform" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
<a href="/examples/emailform.ws3">download</a>
<a name="62"><a href="#toc"><h1>6 checkbox form</h1></a>
This example demonstrates how to handle checkboxes. The user is promted a form to
select checkboxes, to display date informations. <br>
<a href="/examples/checkbox.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
<a href="/bin/examples/checkbox" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
<a href="/examples/checkbox.ws3">download</a>
<a name="72"><a href="#toc"><h1>7 upload file</h1></a>
This example demonstrates a upload form. The user is promted a form to
enter, local file. The file is validated and, if sucessfull,
the server shows in a confirmation the uploaded data back to the user.<br>
<a href="/examples/upload.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
<a href="/bin/examples/upload" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
<a href="/examples/upload.ws3">download</a>
<a name="83"><a href="#toc"><h1>8 sessions</h1></a>
This example demonstrates file-based server-side sessions. Suppose a
customer visits this application for the first time. The application
creates a new session file using <tt>state::init</tt> and stores the
session id in the query string. From now on, <tt>state::init</tt> will know
the session id and re-load the session context - the application
"remembers" the customers settings across multiple HTTP requests using
a session id embedded in all generated URLs. For simplicity, we do not
add shopping items to a shopping cart in this example, but just save
the data of two forms which are presented to the customer. This
involves a little bit of form handling, and this example also
demonstrates error handling in case of unexpected input. But let's
look at the example.<br>
<a href="/examples/session_form.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
<a href="/bin/examples/session_form" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
<a href="/examples/session_form.ws3">download</a>
<a name="103"><a href="#toc"><h1>9 cookie</h1></a>
This example demonstrates how to use cookies. It is very similar to the
session example above.<br>
<a href="/examples/cookie.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a> |
<a href="/bin/examples/cookie" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a> |
<a href="/examples/cookie.ws3">download</a>
<a name="111"><a href="#toc"><h1>10 memory game</h1></a>
This is a more complex example. You know the game "memory", right ?
The goal is to find matching pictures with the least possible number
of tries. The application keeps track of the number of your tries for
a given game and level and compares it with the "hall of fame". This
version does not use sessions except for the "hall of fame", and
stores all information in the URL, which makes the output a little bit
bulky. Have fun.<br>
<a href="/examples/memory.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
<a href="/bin/examples/memory" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
<a href="/examples/memory.ws3">download</a>
1.1 tcl-site/websh/examples.syp
Index: examples.syp
===================================================================
This section presents a selection of sample webshell applications.
All applications are described in detail on this page and come with
richly documented source code. For simplicity, they are all-in-one
files. Plus, they are on-line and ready to use. For each application
discussed below, you will find the corresponding links which present
the code and the live application. Both links will open a new browser
window. You can therefore easily browse through the examples, and look
at the code and the live example simultaneously.
%%%TOC
== hello world ==
In order to get a first impression, let's look at a simple example.
All it does is printing "Hello, world". It consists of one websh
command, =\web::put\=. Basically, =\web::put\= works like Tcl's
=\puts\= command. In addition to printing the text, it does send HTTP
headers when invoked for the first time.\\
%%%HTML <a href="/examples/helloworld.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
%%%HTML <a href="/bin/examples/helloworld" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
=(/examples/helloworld.ws3)(download)=
== command dispatching ==
Now, let's look at one of the main features of websh: the command
dispatching. This allows you to produce all your HTML page from one
and the same source code. This example produces two HTML pages, the
"greetings" page and a "price list" page (even though, for simplicity,
the price list is empty). It uses =\web::dispatch\= to switch into one
of these pages, and =\web::cmdurl\= to produce URLs pointing to each
of these pages.\\
%%%HTML <a href="/examples/dispatch_1.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
%%%HTML <a href="/bin/examples/dispatch_1" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
=(/examples/dispatch_1.ws3)(download)=
== image ==
This example demonstrates how to return an image instead of the
normal "text/html" mime type.\\
%%%HTML <a href="/examples/image.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
%%%HTML <a href="/bin/examples/image" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
=(/examples/image.ws3)(download)=
== confirmation form ==
This example demonstrates a confirmation form. The user is promted a form to
enter, say, order information. The information is validated and, if sucessfull,
an e-mail is sent back to the user.\\
%%%HTML <a href="/examples/emailform.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
%%%HTML <a href="/bin/examples/emailform" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
=(/examples/emailform.ws3)(download)=
== checkbox form ==
This example demonstrates how to handle checkboxes. The user is promted a form to
select checkboxes, to display date informations. \\
%%%HTML <a href="/examples/checkbox.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
%%%HTML <a href="/bin/examples/checkbox" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
=(/examples/checkbox.ws3)(download)=
== upload file ==
This example demonstrates a upload form. The user is promted a form to
enter, local file. The file is validated and, if sucessfull,
the server shows in a confirmation the uploaded data back to the user.\\
%%%HTML <a href="/examples/upload.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
%%%HTML <a href="/bin/examples/upload" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
=(/examples/upload.ws3)(download)=
== sessions ==
This example demonstrates file-based server-side sessions. Suppose a
customer visits this application for the first time. The application
creates a new session file using =\state::init\= and stores the
session id in the query string. From now on, =\state::init\= will know
the session id and re-load the session context - the application
"remembers" the customers settings across multiple HTTP requests using
a session id embedded in all generated URLs. For simplicity, we do not
add shopping items to a shopping cart in this example, but just save
the data of two forms which are presented to the customer. This
involves a little bit of form handling, and this example also
demonstrates error handling in case of unexpected input. But let's
look at the example.\\
%%%HTML <a href="/examples/session_form.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
%%%HTML <a href="/bin/examples/session_form" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
=(/examples/session_form.ws3)(download)=
== cookie ==
This example demonstrates how to use cookies. It is very similar to the
session example above.\\
%%%HTML <a href="/examples/cookie.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a> |
%%%HTML <a href="/bin/examples/cookie" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a> |
=(/examples/cookie.ws3)(download)=
== memory game ==
This is a more complex example. You know the game "memory", right ?
The goal is to find matching pictures with the least possible number
of tries. The application keeps track of the number of your tries for
a given game and level and compares it with the "hall of fame". This
version does not use sessions except for the "hall of fame", and
stores all information in the URL, which makes the output a little bit
bulky. Have fun.\\
%%%HTML <a href="/examples/memory.html" onclick="javascript:window.open('','source','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="source")>source</a>
|
%%%HTML <a href="/bin/examples/memory" onclick="javascript:window.open('','example','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>live example</a>
|
=(/examples/memory.ws3)(download)=
1.1 tcl-site/websh/examples.ws3
Index: examples.ws3
===================================================================
## www.websh.com/whitepaper.html
## nca-115-2
## $Id: examples.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 2
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 3 "webshell example code"}
<tr valign="top">
{navbar_docu 4}
<td width="610">
{includeFile examples.pre}
</td>
</tr>
</table>
}
finishPage 2
1.1 tcl-site/websh/faq.syp
Index: faq.syp
===================================================================
== Generic Questions == generic
-- What is webshell ? -- whatis
webshell is a rapid development environment for building powerful and
reliable web applications. It is a standard Tcl extension and is
released as Open Source Software. webshell is versatile and handles
everything from HTML generation to data-base driven one-to-one page
customization. Netcetera AG, has been using it for years for virtually
all their customer projects, which typically are E-commerce shops or
electronic banking applications.
-- What is the current version ? -- version
Currently, we are finalizing version 3 of webshell. The beta-2
release of webshell is available for download.
-- What does webshell cost ? -- price
Nothing. It's free. webshell is released as Open Source.
-- Where can I download webshell ? -- download
The beta-2 release of webshell is available for download at the
=(download.html)(download area)= of this site.
-- Why should I use webshell ? -- why
In today's E-commerce environment, flexibility and short
time-to-market are key characteristics for successful
business. E-commerce, in other words, calls for a solid basis on which
applications can be built. For exactly this purpose we have designed
webshell.
webshell helps you to create high-quality web applications with light
time constraints. It is fast, versatile, scalable, and easy to learn.
With webshell, you have a win-win situation for developers and
customers.
-- Is there a mailing list ? -- mailinglist
== Technical Questions == technical
-- How do I use the logging facility ? -- logging
Before webshell sends a message to a log destination, the message
needs to pass two filters. That's why you need to specify a level when
you issue a log message. First, webshell decides whether or not to
handle the log message. Then, it scrolls through the list of
registered log destinations and compares the log message level against
the filter of each log destination. The message is sent to the log
destination only if the message passes the second filter.
A log level consists of a tag and a level, separated by a dot.
Possible levels are
==* alert
==* error
==* warning
==* info
==* debug
The tag is free text. Typically, it is the name of the application,
say "foo".
Before log messages can reach their destination, you have to
"open up" the log destination, in two steps:
---
web::logfilter add foo.warning-debug
web::logdest add foo.warning-info file foo_warn.log
web::logdest add foo.debug file foo_dbg.log
---
This sequence of commands tells webshell to handle all messages
in the range "warning" to "debug", if the level string is
"foo", and to discard any other messages. Messages of level
"debug" are then written to file "foo_dbg.log", while
the other messages end up in file "foo_warn.log".
Issuing a message is easy:
---
web::log foo.info "Hello, world !"
---
1.1 tcl-site/websh/faq.ws3
Index: faq.ws3
===================================================================
## www.websh.com/faq.html
## nca-115-2
## $Id: faq.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 3
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 4 "frequently asked questions"}
<tr valign="top">
{navbar_supp 1}
<td width="455">
{includeFile faq.pre}
</td>
{newsbar_supp}
</tr>
</table>
}
finishPage 3
1.1 tcl-site/websh/helloworld.sample
Index: helloworld.sample
===================================================================
#! ../../bin/websh3
web::put "Hello, world"
1.1 tcl-site/websh/image.sample
Index: image.sample
===================================================================
#! ../../bin/websh3
# gif sample - return a image/gif instead of text/html
#
# this example demonstrates how to use cookies with websh3
#
web::command image {
set nr [format %2.2d [expr int(rand() * 30)]]
# open a file (JPEG is a binary format)
set fh [open ../../docs/examples/memory/$nr.jpg r]
fconfigure $fh -translation binary
set img [read $fh]
close $fh
# set HTTP header to "image/jpeg" instead of "text/html"
array set headers [web::response -set header]
set headers(Content-Type) image/jpeg
web::response -set header [array get headers]
# because we return a img, change to binary again
fconfigure [web::response] -translation binary
# output
web::put $img
}
# produce the page of this sample application
proc page {} {
web::put "<html><head><title>Image Example</title></head>"
web::put "<body bgcolor=\"#FFFFFF\">"
# the images: returned by the same app, but a different command
web::put "<img src=\"[web::cmdurl image]\" width=\"50\" height=\"50\"\"><br>"
web::put "<a href=\"[web::cmdurl default]\">next</a>"
# properly close html code
web::put "</body></html>"
}
web::command default {
page
}
# dispatch (see "dispatch_example")
web::dispatch
1.1 tcl-site/websh/index.ws3
Index: index.ws3
===================================================================
## www.websh.com/index.html
## nca-115-2
## $Id: index.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
#web::response -sendheader 0
# source [file join [file dirname [web::request SCRIPT_FILENAME]] websh.com.gen]
startHtmlPage
startHtmlBody
putHeader 0 0
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
<tr height="30">
<td width="300" rowspan="2" valign="top"><img height="380" width="300" src="images/headline.gif" alt="Headline"></td>
<td width="315" height="30"><h1>Welcome</h1></td>
<td width="10" rowspan="2"></td>
<td width="140" height="30"><h1>News</h1>
</td>
</tr>
<tr valign="top">
<td width="315"><img height="160" width="120" src="images/drei_klein.gif" align="left">
The Internet is growing rapidly. Daily you find new
applications and new home-pages - new opportunities for
success and profit. The basic technologies behind the
Internet, however, have remained stable for years. Only on
a solid basis can you build new stuff.<br>
<br>
<!-- Since 1996, Netcetera's success has been based on webshell.
This rapid development environment for building powerful web
applications is rock solid, but by no means a monolith: the
webshell rather is the glue to assemble complex
applications. Netcetera continues this traditionally
innovative concept with webshell 3.<br>
<br>
-->
</td>
<td width="140">
<table border="0" cellpadding="0" cellspacing="0" width="145">
{newsBarElement "Newsletter" \
{<FORM action="/bin/mail/websh_news?cmd=subscribe" method="POST">
<INPUT TYPE="TEXT" SIZE="10" MAXLENGTH="35" NAME="user">
<INPUT type="submit" value="join">
</FORM>
}
}
{newsBarElement "websh 3.0.0 available:" \
{pick the {pageLink /downloaddir/websh-3.0.0.tar.gz -show "tarball"}
or browse the {pageLink /download.html -show "download area"}.
}
}
{newsBarElement "Examples" \
{ Check out the<br> {pageLink /examples.html -show "live examples"}<br>
of Webshell applications.
}
}
</table>
<br>
</td>
</tr>
</table>
}
finishPage
1.1 tcl-site/websh/install.tcl
Index: install.tcl
===================================================================
#!/usr/local/bin/tclsh8.3
# install.tcl -- helper for install
# nca-115-2
# $Id: install.tcl,v 1.1 2002/05/08 10:31:09 davidw Exp $
# usage: install.tcl src dest chmod
if {$argc != 3} {
puts "($argc) usage: install.tcl src dest chmod"
exit 1
}
set src [lindex $argv 0]
set dest [lindex $argv 1]
set chmod [lindex $argv 2]
set doInstall 0
if { ![file exists $src] } {
puts "install.tcl - $src does not exist - skip"
return
}
if { [file exists $dest] } {
if {[file mtime $src] > [file mtime $dest]} {
file delete $dest
set doInstall 1
}
} else {
set doInstall 1
if { ![file exists [file dirname $dest]] } {
puts "install.tcl - making [file dirname $dest]"
file mkdir [file dirname $dest]
}
}
if {$doInstall} {
puts -nonewline "install.tcl - installing $dest ... "
file copy $src $dest
file attributes $dest -permissions $chmod
puts "done"
}
1.1 tcl-site/websh/memory.sample
Index: memory.sample
===================================================================
#! ../../bin/websh3
#
# short intro
#
# game "memory": the player is supposed N pairs of pictures with the
# least possible amount of tries. We thus keep track of:
# s the current status of the pictures
# 0 backside up
# 1 front up
# 2 permanently open
# i the array of pictures used for this game
# (varies with each reshufflement)
# l the current level (translates into N)
# h which pictures have been "hit", ie selected by the player
# r the refresh rate
#
# the application needs to
# * reshuffle --> generate new i
# * find matching --> check/modify status
# * change level --> keep track of l and reshuffle
# * show help text
# * change refresh rate
# * keep track of best player
#
# turn logging on
web::logfilter add memory.-debug
web::logdest add memory.-debug file [file join / tmp memory.log]
# config: map level number to X-Y dimensions
set _levels(1) [list 1 2]
set _levels(2) [list 1 4]
set _levels(3) [list 2 5]
set _levels(4) [list 3 6]
set _levels(5) [list 4 7]
set _levels(6) [list 5 8]
set _levels(7) [list 6 9]
# setup file context
web::filecontext mctx -path [file join .. .. data %s.ctx]
# formatLink -- helper function to generate hrefs
proc formatLink {url {show ""}} {
if {$show == ""} { set show $url }
return "<a href=\"$url\">$show</a>"
}
# putLink -- helper function to output links
proc putLink {url {show ""}} {
web::put [formatLink $url $show]
}
# putLinkHtmlified -- helper function to output links
proc putLinkHtmlified {url show} {
web::put [formatLink $url [web::htmlify $show]]
}
# commandList -- add "commands" line to HTML page
proc commandList {} {
web::put "<tt>"
putLinkHtmlified [web::cmdurl decrementLevel] "<"
web::put " | "
putLinkHtmlified [web::cmdurl incrementLevel] ">"
web::put " | "
putLinkHtmlified [web::cmdurl reset] "x"
web::put " | "
putLinkHtmlified [web::cmdurl new] new
web::put " | "
putLinkHtmlified [web::cmdurl help] "?"
web::put " | "
putLinkHtmlified [web::cmdurl incrRefreshTime] "+"
web::put " | "
putLinkHtmlified [web::cmdurl decrRefreshTime] "-"
# load hall of fame
mctx::init memory
# get the lowest number of tries for this level from the session context
# why do I use web::cmdurlcfg here instead of web::param ?
# I do not want to bother about the level when I generate a URL
# using web::cmdurl - I keep it in the static parameters (managed
# by web::cmdurlcfg).
set best [mctx::cget hof([web::cmdurlcfg l]) "n/a"]
web::put " (level: [web::cmdurlcfg l], [web::cmdurlcfg c] tries, best: $best)"
web::put "</tt>\n"
web::put "<br>\n"
}
# page -- helper function to produce an HTML page
proc page {title code} {
# HTML header stuff
web::put "
<html>
<head>
<title>$title</title>
</head>
<body bgcolor=\"#ffffff\">
"
web::put "<br>\n"
# depends on the caller
uplevel 1 $code
# add list of commands
web::put "<hr>\n"
commandList
# footer and end-of-HTML
web::put "
<hr><font size=\"-2\"><tt>
[web::copyright -version]</tt></font><br>
</BODY>
</HTML>
"
}
# table -- helper function to output a HTML table
proc table {code} {
web::put {<table border="0" cellspacing="0" cellpadding="0">}
web::put "\n"
uplevel 1 $code
web::put "\n</table>\n"
}
# tablerow --
proc tablerow {code {bgcolor {}}} {
if {[string length $bgcolor] } {
web::put "<tr bgcolor=\"$bgcolor\">\n"
} else {
web::put "<tr>\n"
}
uplevel 1 $code
web::put "\n</tr>\n"
}
# tablecell --
proc tablecell {code} {
web::put "<td>\n"
uplevel 1 $code
web::put "\n</td>\n"
}
# image --
proc image {gif} {
set res "<img src=\"/examples/memory/$gif\" width=\"50\" height=\"50\" vspace=\"0\" hspace=\"0\""
append res "border=\"1\" ALIGN=\"middle\">"
return $res
}
# validateImg -- check current game status
proc validateImg {vImg vStatus} {
global _levels
upvar $vImg img
upvar $vStatus status
# no images - this calls for a new game. Reshuffle.
if { [string length $img] < 2} {
# reset try counter
web::cmdurlcfg -set c 0
# get current level
set tmp $_levels([web::cmdurlcfg l])
# reshuffle (number of images depends on level)
set numImg [expr ([lindex $tmp 0] * [lindex $tmp 1]) / 2]
for {set i 0} {$i < $numImg} {incr i} {
set timg [format %2.2d $i]
# for this image, generate two random numbers which will
# determine the position of the image in the game
while {1} {
set r1 [expr rand()]
if { ![info exists shuffle($r1)] } { break }
}
while {1} {
set r2 [expr rand()]
if { ![info exists shuffle($r2)] } { break }
}
set shuffle($r1) $timg
set shuffle($r2) $timg
}
# compile string which describes game outline
set img ""
foreach tmp [array names shuffle] {
append img $shuffle($tmp)
}
# and set status of every image to "closed"
set status [string repeat "0" [expr $numImg * 2]]
}
}
# listOpen -- helper function to list currently open pictures
proc listOpen {vStatus {val 1}} {
upvar $vStatus status
set i 0
set res ""
foreach tmp [split $status ""] {
if { $tmp == $val } {lappend res $i}
incr i
}
return $res
}
# countOpen -- helper to count all pictures that have a given status
proc countOpen {vStatus {val 1}} {
upvar $vStatus status
set res [listOpen status $val]
return [llength $res]
}
# doMatch -- helper to decide if two selected images match
proc doMatch {vImg vOpens} {
upvar $vImg img
upvar $vOpens opens
set img1 [getImageFromArray img [lindex $opens 0]]
set img2 [getImageFromArray img [lindex $opens 1]]
if {[string equal $img1 $img2]} {
set res [list 1]
lappend res [lindex $opens 0]
lappend res [lindex $opens 1]
} else {
set res [list 0]
lappend res [lindex $opens 0]
lappend res [lindex $opens 1]
}
return $res
}
# getImageFromArray -- helper to extract two letters from string
proc getImageFromArray {vImg pos} {
upvar $vImg img
return [string range $img [expr $pos*2] [expr $pos*2 + 1]]
}
# getStat -- helper to pick status for a given picture
proc getStat {vStatus pos} {
upvar $vStatus status
return [string index $status $pos]
}
# setStat -- set status
proc setStat {vStatus pos {new 0}} {
upvar $vStatus status
set res [string range $status 0 [expr $pos - 1]]
set res $res$new
set res $res[string range \
$status [expr $pos + 1] [string length $status]]
set status $res
}
# toggleStat -- toggle status: switch 0->1 or 1->0, but keep 2 at 2
proc toggleStat {vStatus pos} {
upvar $vStatus status
set cur [getStat status $pos]
if {$cur == 0} {
setStat status $pos 1
} elseif { $cur == 2 } {
setStat status $pos 2
} else {
setStat status $pos 0
}
}
# findMatching -- see if the user did find two matching images
proc findMatching {vImg vStatus} {
upvar $vImg img
upvar $vStatus status
# in case only one is open, we prevent closing it again
set tmp [listOpen status 1]
set onlyone -1
if { [llength $tmp] == 1 } {
set onlyone [lindex $tmp 0]
}
# which ones are selected ?
set hitlst [web::param h]
foreach tmp $hitlst {
# if it is not the single one that is already open, flip it
if {$tmp != $onlyone} {
toggleStat status $tmp
}
}
# now, how many are open, really ?
set opens [listOpen status]
set Nopen [llength $opens]
# more than two open ? (no tricks !)
if { $Nopen > 2 } {
foreach tmp $opens {
setStat status $tmp 0
}
} elseif { $Nopen == 2 } {
# get current try counter (or 0 if not set) ...
set tmp [web::cmdurlcfg c 0]
# ... and increment it and store it back as static parameter
web::cmdurlcfg -set c [incr tmp]
# do the two selected pictures match ?
set tmp [doMatch img opens]
if { [lindex $tmp 0] == 1 } {
# yes, open permanently
setStat status [lindex $tmp 1] 2
setStat status [lindex $tmp 2] 2
} else {
# no. use the refresh feature
set opens [listOpen status]
# add img and status as static parameters
# (ensure that we have status and img in the URL)
web::cmdurlcfg -set s $status
web::cmdurlcfg -set i $img
# for refresh: simulate clicks on the two open pictures
# that will close them
set tmp [web::cmdurl "" [list h [lindex $opens 0] h [lindex $opens 1]]]
# add the HTTP "refresh" header, using the parameter r for the
# refresh time (using 2 sec as default)
web::response -set Refresh "[web::cmdurlcfg r 2];URL=$tmp"
}
}
# add img and status as static parameters
# (ensure that we have status and img in the URL)
web::cmdurlcfg -set s $status
web::cmdurlcfg -set i $img
}
# display table with memory
proc showMemory {} {
global _levels
global _cache
# get current status from URL
set status [web::param s]
# get current game outline from URL
set img [web::param i]
# asses status of game
validateImg img status
# do we have any matching images ?
findMatching img status
# no more closed ? --> game over --> perhaps we need to update hof
if { [countOpen status 0] == 0} {
mctx::init memory
set best [mctx::cget hof([web::cmdurlcfg l]) -1]
if { ($best == -1) ||
([web::cmdurlcfg c] < $best) } {
mctx::cset hof([web::cmdurlcfg l]) [web::cmdurlcfg c]
mctx::commit
}
}
# get X-Y dimension for game outline from level
set tmp $_levels([web::cmdurlcfg l 5])
set numX [lindex $tmp 0]
set numY [lindex $tmp 1]
# output HTML page
page "memory game" {
# output HTML table
table {
# table rows
for {set i 0} {$i < $numX} {incr i} {
tablerow {
for {set j 0} {$j < $numY} {incr j} {
set tmpCnt [expr $i * $numY + $j]
set timg [getImageFromArray img $tmpCnt]
set curImgStat [getStat status $tmpCnt]
# table cells
tablecell {
if {$curImgStat == 0} {
# show backside
#
# actually, it is a link back to the CGI app,
# recursion of some sort.
#
# from parameter h, showMemory will know which
# picture the player did select
putLink [web::cmdurl "" h $tmpCnt] \
[image back.gif]
} elseif {$curImgStat == 2} {
# two matching found - no link any more, just the image
web::put [image $timg.jpg]
} else {
# show front side
putLink [web::cmdurl "" h $tmpCnt] \
[image $timg.jpg]
}
}
}
}
}
}
}
}
# web::command help -- display help text
web::command help {
page "memory game - help text" {
web::put "<tt>"
web::put "Memory -- find the matching images."
web::put "<p>"
web::put "You can see the hidden image by clicking on its back side. "
web::put "When you have found two matching images, they will remain open "
web::put "from then on. If two images do not match, they will be "
web::put "closed again."
web::put "<p>"
web::put "If the images close again too quickly on your system, "
web::put "you can make the images stay open longer with the "
web::put ""+" command ("-" to close them "
web::put "more quickly)."
web::put "<p>"
web::put ""new" shuffels the images again. "
web::put ""×" restarts the game from the beginning."
web::put "</tt><p>"
}
}
# web::command decrementLevel -- reduce level and show game
web::command decrementLevel {
# I do not want to have to bother about the level when I generate
# URLs using web::cmdurl. So, I put level to the static parameters
# and let web::dispatch track it.
# That's why web::cmdurlcfg is used here, instead of web::param.
set level [web::cmdurlcfg l 5]
if {$level > 1} {incr level -1}
web::cmdurlcfg -set l $level
# changing the level implies resetting the game
web::param -set i ""
showMemory
}
# web::command incrementLevel -- increase level and show game
web::command incrementLevel {
set level [web::cmdurlcfg l 5]
if {$level < 7} {incr level}
web::cmdurlcfg -set l $level
# changing the level implies resetting the game
web::param -set i ""
showMemory
}
# web::command incrRefreshTime -- increase refresh time
web::command incrRefreshTime {
set r [web::cmdurlcfg r 2]
if {$r < 30} {incr r 2}
web::cmdurlcfg -set r $r
showMemory
}
# web::command decrRefreshTime -- decrease refresh time
web::command decrRefreshTime {
set r [web::cmdurlcfg r 2]
if {$r > 2} {incr r -2}
web::cmdurlcfg -set r $r
showMemory
}
# web::command new -- new game on the same level (reshuffle)
web::command new {
web::param -set i ""
showMemory
}
# web::command reset -- back to the defaults
web::command reset {
web::param -set i ""
web::cmdurlcfg -set l 5
showMemory
}
# web::command default -- if nothing is specified, use this one
web::command default {
showMemory
}
# web::dispatch -- decide which command to call
#
# here, we use the tracking feature of dispatch. Whenever dispatch
# finds a parameter from the -track list, it copies it over to the
# static parameters
#
# also, we use -hook to execute code just before web::dispatch will
# call the web::command command. Here, we set the default level to 5
# if it is not yet known.
web::dispatch -track [list l c r] -hook {
web::cmdurlcfg -set l [web::cmdurlcfg l 5]
}
1.1 tcl-site/websh/privacy.ws3
Index: privacy.ws3
===================================================================
## www.websh.com/privacy.html
## nca-115-2
## $Id: privacy.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 0
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 3 "Our Privacy Policy"}
<tr valign="top">
{navbar_null}
<td width="455">
At {pageLink websh.com -pre} you have <b>full control</b> over
your personal information.<br>
We do not track who you are or what you are doing at this site, we
do not use cookies, and we are not giving information away about
you (which is easy, since we do not collect information in the
first place).
</td>
</tr>
</table>
}
finishPage
1.1 tcl-site/websh/product.ws3
Index: product.ws3
===================================================================
## www.websh.com/product.html
## nca-115-2
## $Id: product.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 1
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 4 "webshell described" "characteristics"}
<tr valign="top">
{navbar_prod 0}
<td width="455">
<img height="160" width="150" src="images/ausschnitt_product.gif" align="left" alt="graphics">
webshell is a rapid development environment for building
powerful, fast, and reliable web applications. webshell is
versatile and handles everything from HTML generation to
data-base driven one-to-one page customization. We have been
using it for years for virtually all our customer projects,
which typically are E-commerce shops or electronic banking
applications. webshell is extensible and portable, and its
comprehensive set of commands is quickly learned.
<h2>Open Source Software</h2>
webshell is released as open source software. The source code as
well as binaries for a selection of platforms are available for
download for free. webshell users have full control over and
insight into webshell. This is protection of investment.
<h2>Apache 2 module</h2>
webshell is scalable. Its CGI interface ensures that webshell
can be employed virtually everywhere, using off-the-shelf web
servers. If performance is key, the webshell Apache 2 module
gives you lightening-fast one-to-one content. And the nice
thing: for both the CGI environment and for the Apache 2 module,
you use exactly the same webshell application. <br><br>
</td>
<td width="10"></td>
<td width="145">
<table border="0" cellpadding="0" cellspacing="0" width="145">
{redPointElement "Open Source"}
{redPointElement "Apache 2 module"}
{redPointElement "Tcl Extension"}
{redPointElement "Thread Safe"}
{redPointElement "Modular Design"}
{redPointElement "Extensible"}
<tr>
<td colspan="2" height="30">
<br><h1>key features</h1>
</td>
</tr>
{redPointElement "web transaction state management"}
{redPointElement "session management"}
{redPointElement "strong encryption (extensible)"}
{redPointElement "fast logging facility (extensible)"}
</table>
</td>
</tr>
{uppfeil product.html -text "webshell history" -aName history}
<tr valign="top">
<td width="10"></td>
<td width="150"></td>
<td width="455">
The development of Websh began in 1996. Websh
has since been successfully used in virtually all customer
projects of Netcetera. Why does a technology-driven company
like Netcetera rely on a tool with such a slow release cycle ?
Good design pays off.<br><br>
While the Internet changes at a rapid pace, the underlying
technologies remain stable, and Websh has been built to
handle them. The practical experience gained from the
day-to-day use of Websh has now been channeled into the
current release, Websh 3. <br><br>
</td>
</tr>
{uppfeil product.html -text "Based on Tcl" -aName tcl}
<tr valign="top">
<tr valign="top">
<td width="10"></td>
<td width="150"></td>
<td width="455">
Websh is based on the Tool Command Language (Tcl,
pronounced "tickle"). Tcl is a fast, comprehensive
scripting language as well as a library. The Tcl
development started 1987 at the University of California at
Berkeley with John K.Ousterhout. Today, Ousterhout is CEO of
"Scriptics Corporation", which continues to develop Tcl, and
markets value added products for Tcl.<br><br>
The decision to build Websh on top of Tcl has several
advantages which can be summarized as
"flexibility". <b>Figure 1</b> gives an overview
of the Websh Architecture.<br><br>
<img src="images/ws3ov.gif" alt="Websh Architecture"><br>
<b>Figure 1</b> - Websh Architecture<br><br><br>
Most Web-based applications need to separate items with a
high change rate from other, static parts. In other words,
<b class=blue>configurability</b> is needed. For
example, HTML output must be changeable without the need to
recompile the application.<br><br>
Using Tcl as an embedded system, such configurable parts can
be designed as Tcl code snipplets and configuration files.
<br><br><br>
Web-based applications demand a high degree of flexibility
or <b class=blue>extensibility</b> . In particular, it
must be straight-forward to add new functionality. Websh
does not manage data base access, for example, but rather
relies on proven Tcl extensions for this task. Choosing Tcl
for Websh thus ensures the extensibility of Websh
itself.
<br><br><br>
Finally, Web-based applications must be deployable on a wide
range of platforms. Tcl has been ported to all important
operating systems. Embedding Tcl thus ensures the <b
class=blue>portability</b> of Websh. <br><br><br>
</td>
</tr>
{uppfeil product.html -text "Websh Design" -aName design}
<tr valign="top">
<tr valign="top">
<td width="10"></td>
<td width="150"></td>
<td width="455">
Websh has a modular design, particularly for thread
safety.Each module manages its own data, and locking
mechanisms are used where needed. Websh modules are
extensible through plug-Ins.<br>
<b>Figure 2</b> gives an overview of the Websh
modules. In the following, each module is shortly
described.<br> <img src="images/ws3arch.gif" alt="Websh 3
Design"><br>
<b>Figure 2</b> - Websh 3 modules<br>
<h2>request and url management</h2>
The Websh application developer does not need to get
involved with the details of the HTTP protocol or the
parsing of data. Rather, he concentrates on the application
logic and leaves the rest to Websh. This module parses
input from the browser, e.g. HTML form data, and makes it
available to Websh. <br><br>
One of the distinctive features of Websh is its state
management capability. Web-based applications often need to
carry information from one HTTP transaction to the next. As
an example, the user will choose his preferred language.
Applications for electronic commerce systems, Internet
banking and so on also need mechanisms to identify and group
transactions into longer transactions which cover more than
one single HTTP request and its response. This Websh
module introduces state.
<h2>session management</h2>
Websh provides sessions for transaction data management as
well. For example, a Websh application would store the
items in a "shopping cart" in a session context. The session
management module handles session data, which can be stored
on the client side using Netscape cookies; or on the server
side using the file system (fs), a data base management
system (DBMS), or the Netcetera cache manager (ncm). The
module provides a uniform interface to access the session
context regardless of the storage used. It is implemented
in Tcl and makes extensive use of namespaces.
<h2>output management</h2>
Websh provides commands to format HTTP-compliant output
to be sent back to the client. output can be directed to Tcl
channels or to Tcl variables for buffering purposes. The
output management module is fully configurable to give the
user control over the generated output.
<h2>conversion</h2>
Need HTML compliant input ? Want to send data via an URL, or
in a form field ? This module converts umlauts to their
proper HTML entities or their URI encoded equivalent, for
example. As do all Websh modules, the conversion module
manages its data on its own, thus ensuring thread safety.
<h2>security by encryption</h2>
The proper handling of sensitive data is crucial for banking
or E-commerce applications. Three aspects are important:
Data transfer, data storage, and session hijacking. This
Websh module provides the commands to encode and decode
data, and to manage pass-phrases and encryption methods.
<br><br>
Websh relies on well-known and well-tested encryption
methods, which are made available to Websh by means of
plug-ins.<br>
<h2>messages on streams</h2>
This Websh module implements a simple protocol to facilitate
communication over Tcl channels. Particularly, it is used for
communication over TCP/IP connections.
<h2>logging facility</h2>
Web applications need a versatile logging mechanism to
report errors and other information. In fact, Websh
itself makes heavy use of the logging facility. Logging must
be easy to use, fast, and extensible. Typically, Websh
applications handle hundreds of requests per second, and the
logging facility has been designed with this kind of load in
mind. <br><br>
The logging module is extensible through plug-Ins.
<br><br><br>
Find more information in the
{pageLink whitepaper.html -show "Websh white paper"}.
</td>
</tr>
</table>
}
finishPage 1
1.1 tcl-site/websh/quickref.syp
Index: quickref.syp
===================================================================
%%%TITLE webshell quick reference
%%%TOC
-- general remarks --
webshell 3.0 embeds a Tcl 8.3 interpreter, and all Tcl 8.3 commands
are available, too.
Typically, webshell commands have the following syntax:
=/web::acommand ?options? ?subcommands ? ?arguments?/=.
Options start with a dash ("-"). As usual, dash-dash ("--") indicates
the "end-of-options". Thus, =/web::acommand -o1 a1 -- -o2/=
takes "-o2" as the first argument.
In difference to the normal "set" behaviour of tcl and webshell,
configuration commands of webshell normally return the previously
used value when a new value is set.
In addition to the examples given here you might find
=(http://websh.com/examples.html)= a usefull source of information.
== configuration ==
-- web::config --
==D syntax
=|web::config|= <key> ?<value>?\\
<key>: =|uploadfilesize|=, =|cmdparam|=, =|timeparam|=,
=|logsubst|=, =|putxmarkup|=, =|version|=, =|copyright|=,
=|encryptchain|=, and =|decryptchain|=\\
If <value> is ommitted, the current value of <key> is returned.
==D uploadfilesize ?<size>?
Sets the maximum number of bytes allowed to be uploaded.
Default: 0.
==D cmdparam ?<name>?
Name of the parameter to store reference to a web::command command
in the URL. Default: "cmd".
==D timeparam ?<name>?
Name of the parameter to store reference to the timestamp
in the URL. Default: "t".
==D logsubst ?<boolean>?
Turns substitution of log messages on or off. Default: on.
==D putxmarkup ?brace|tag?
Sets the markup characters for sections to be eval'd in web::putx
and web::putxfile commands to either curly braces ({ ... }) or
special tags (<% ... %>). Please note that when using the tags <%%>,
they cannot be nested. Default: brace.
==D version
Returns the version info string
==D copyright
Returns a copyright message string
==D encryptchain <list>
defines which commands should be tried, in sequence, to encrypt
a message. Default: "web::encryptd"
==D decryptchain <list>
defines which commands should be tried, in sequence, to decrypt
a message. Default: "web::decryptd"
-- Examples --
--- ---------------------------------------------------------------------------
web::config decryptchain
==> web::encryptd
--- ---------------------------------------------------------------------------
== command dispatching and session management ==
webshell provides a command dispatching mechanism to produce, for
example, different HTML pages within one application. The name of the
command to be used is encoded in the querystring (see =\web::cmdurl\=
for details on how to produce such querystrings). Command dispatching
is initiated with the command =\web::dispatch\=. Commands are defined
with =\web::command\=.
-- web::command --
==D Syntax:
=|web::command|= ?<cmdName>? <cmdBody>
Registers <cmdBody> as <cmdName>. If <cmdName> is
omitted, "default" is used.
-- web::getcommand --
==D Syntax:
=|web::getcommand|= ?<cmdName>?
Retrieves the body of the command <commandName> or of the command "default"
if <cmdName> is omitted.
-- web::cmdurl --
==D syntax
=|web::cmdurl|= ?options? <cmdName> ?<key-value-list>?\\
=|web::cmdurl|= ?options? <cmdName> <k1> <v1> ... <kN> <vN>\\
Options are: =\-notimestamp\=, and \=-urlformat\=
Generate URLs including querystring. By default, URLs are
self-referencing, but the exact output is subject to configuration. The
querystring is encrypted, using the encryption method specified by
configuration (see =\web::config\=). If <cmdName> is "", no command parameter
is produced in the query string.
==D -notimestamp
do not add a timestamp to the URL
==D -urlformat <list>
specify what items will be used to format just this URL.
Default is: =\{scriptname pathinfo querystring}\=\\
Use =\web::cmdurlcfg\= to define the url format for all
URLs produced by =\web::cmdurl\= in one request.\\
==D scheme
include the protocol, only "http" and "https" are currently supported
==D host
include the host name, e.g. "websh.com"
==D port
include the port, e.g. "80"\\
Trying to set this item without host will throw
an error
==D scriptname
include scriptname, e.g. "/cgi-bin/orderbooks"
==D pathinfo
include pathinfo, e.g. "/merchants/shop1"
==D querystring
include the querystring, e.g. "select=download"
Note that there are two more commands that control the output of
=\web::cmdurl\=: =\web::config cmdparam\= and =\web::config timeparam\=.
-- Examples --
--- ---------------------------------------------------------------------------
web::cmdurl -notimestamp -urlformat [list scheme host scriptname pathinfo querystring] "test"
==> http://websh.com/bin/returnmail/member?XDZuRD2rnsfHjFH
--- ---------------------------------------------------------------------------
-- web::cmdurlcfg --
==D syntax
=|web::cmdurlcfg|= ?options? ?<key>? ?<value>?\\
Exactly like =\web::param\=\\
=|web::cmdurlcfg|= option ?<value>?\\
Options are =|-scheme|=, =|-host|=, =|-port|=,
=|-scriptname|=, =|-pathinfo|=, =|-querystring|=, =|-urlformat|=\\
If <value> is omitted, the current value is returned.
Otherwise, the <value> is stored.
Configuration for web::cmdurl. This command serves two purposes:
==1 management of static parameters
==1 configuration for =\web::cmdurl\=
.. management of static parameters ..
In order to set, retrieve, append or unset static parameters,
use the syntax of the =\web::param\= command, for example:
==D web::cmdurlcfg -set <key> <value>
add the static parameter <key>
==D web::cmdurlcfg
returns a list of all known static parameters
=|Important|=: =\web::cmdurl\= compares every key from the static
parameters (see =\web::cmdurlcfg\=) against the keys from the command
line. The static parameter is only used if there is no parameter given
on the command line.
.. configuration for =\web::cmdurl\= ..
==D web::cmdurlcfg -protocol ?<value>?
protocol to be used. Default: http.
==D web::cmdurlcfg -servername ?<value>?
server name to be used. Default: taken from request.
==D web::cmdurlcfg -port
port number to be used. Default: 80.
==D -scriptname
name of CGI executable. Default: taken from request.
==D -pathinfo
path info (path after scriptname). Default: taken from request.
==D -urlformat <list>
changes the urlformat permanently. See web::cmdurl for the
description of this option
In all cases, "web::cmdurlcfg -option <value>" sets the value of
the given option and returns the value that was used before the change,
while "web::cmdurlcfg -option" returns the current value. If no value
has been set using web::cmdurlcfg, but is requested for the URL
generation, the value from the request will be used. This value,
however, can not be retrieved using web::cmdurlcfg.
Note that setting a value to an empty string amounts to "unset".
=|Note also|=: web::cmdurl compares every key from the static
parameters see -->(web::cmdurlcfg) against the keys from the command
line. The static parameter is only used if there is no such parameter on
the command line.
-- Examples --
--- ---------------------------------------------------------------------------
% web::cmdurl
==> ?XD8Fseb6tjYQsBUWZ9
% web::cmdurlcfg -scriptname bin/test_script
% web::cmdurl
==> bin/test_script?XD8Fseb6tjYRl1M9Fl
% web::cmdurlcfg -scriptname ""
% web::cmdurl
==> ?XD8Fseb6tjYQsBUWZ9
--- ---------------------------------------------------------------------------
-- web::dispatch --
==D syntax
=|web::dispatch|= ?options?\\
Options are: =\-cmd\=, =\-querystring\=, =\-postdata\=,
=\-track\= and =\-hook\=
Parse information and call a command.
==D web::dispatch -cmd <cmdName>
switch into command <cmdName>. If <cmdName> is an empty string,
no command is called. By default, <cmdName> is taken from
the querystring.
==D web::dispatch -querystring <string>
parse <string> as querystring. If <string> is an empty string,
querystring parsing is turned off. By default, querystring is
taken from the request data (CGI environment or apache module
request object).
==D web::dispatch -postdata <string> ?<content_type>?
parse <string> as POST data input with type <content_type>.
<content_type> can be =\application/x-www-form-urlencoded\= or
=\multipart/form-data; boundary=xxx\=. In the second case,
<content-type> must specify the boundary as well. By default,
POST data is taken from the request data.\\
If <string> is an empty string, postdata parsing is turned off.\\
Default for <content_type> is "application/x-www-form-urlencoded"
==D web::dispatch -postdata <channelName> <content_length> <content_type>
As above, but reads the POST data from channel <channelName>.\\
Use the keyword =\end\= for <content_length> to indicate that
websh should read all content.\\
Examples for <content_type> include:
==* =\multipart/form-data; boundary=xxxx\=
==* =\application/x-www-form-urlencoded\=
==D web::dispatch -track <paramKeyList>
Track a parameter: register it as "static" for the generation of
URLs with web::cmdurl. Thus, each parameter with the key in
<paramKeyList> will be repeated in every URL generated with
web::cmdurl. See the documentation of web::cmdurl for details.
==D web::dispatch -hook <code>
Causes web::dispatch to eval <code> just before the command (from
any source) is evaluated. When <code> is evaluated, the full
request information has been parsed. That is, web::param,
web::formvar etc. will have up-to-date information when
<code> is evaluated.
=|Note|= that, if no command is passed to web::dispatch either in the
querystring or with the -cmd option, web::dispatch will call the
command "default".
-- Examples --
--- ---------------------------------------------------------------------------
set tst {puts "On the hook"}
web::command acmd { puts "this is acmd" }
web::dispatch -cmd acmd -querystring "" -postdata ""
==> this is acmd
web::dispatch -cmd acmd -querystring "" -postdata "" -hook $tst
==> On the hook
==> this is acmd
--- ---------------------------------------------------------------------------
-- session management --
Webshell session management consits of two parts:
==* session id tracking
==* session context management
Session context managers are described in detail below
(=|web::filecontext|=, =|web::cookiecontext|=). Session id tracking is
managed by =\web::dispatch -track\=. The two parts are connected with
the =|-attachto|= option of the session context manager. The control
is as follows:
==* a user uses the Webshell script for the first time.
=\web::dispatch -track\= will not see any session id, and,
consequently, not set the static parameter =\id\=.
==* Within the application, the session is initialized
using =\<mgr>::init\=. =\init\= will find no static
parameter =\id\= (which has been specified at creation
time of the session manager using the =\-attachto\= option).
Now, it tries to create a new session id. This will be
possible if a session id generator has been specified
when the manager was created using the =\-idgen\= option.
From now, on the session id will be a static parameter, and
will therefore be present in every URL generated with
=|web::cmdurl|=
==* The next time the user visits the Webshell application using
one of these URLs, =|web::dispatch|= will detect the session
id, and =|<mgr>::init= will directly load the corresponding
session context without generating a new session id.
-- Examples --
See =(http://websh.com/examples.html)= for several sample
application demonstrating the session management of Webshell.
== request data handling ==
-- web::request --
==D syntax
=|web::request|= ?options? ?<key>? ?<value> ...?\\
=|web::request|= ?<key>? ?<default>?\\
Options are: =\-count\=, =\-set\=, =\-lappend\=, =\-names\=, =\-unset\=, =\-reset\=
and =\-channel\= fixme: gibt es -channel noch?
web::request is an accessor to CGI related information.
==D web::request
returns a list of all known keys
==D web::request <key> ?<default>?
returns the value for <key>. Can be a list. In case
that <key> does not exist, return <default>, if it is
given, or an empty string.
==D web::request -count <key>
returns number of items in list for <key>; returns 0 if
<key> does not exist
==D web::request -set <key>
does the same as 'web::request <key>'
==D web::request -set <key> <value> ?<value> ...?
adds the parameter <key> to the web::request data.
Any existing parameters with <key> are overwritten
==D web::request -lappend <key> <value> ?<value> ...?
append parameters with the same <key> to the web::request data. In
this case the existing <value> is not overwritten
==D web::request -unset
deletes all parameters from the web::request data
==D web::request -unset <key>
deletes a parameter from the web::request data
==D web::request -reset
deletes all parameters from the web::request data (like 'web::request -unset'),
removes all static parameters (like 'web::cmdurlcfg -unset'), all form variables
(like 'web::formvar -unset'), all query string parameters (like 'web::param -unset'),
and all temporary files created by HTTP form upload
==D web::request -channel
fixme: what does it?
-- web::param --
==D syntax
=|web::param|= ?options? ?<key>? ?<value> ...?\\
Options are: =\-count\=, =\-set\=, =\-lappend\=, =\-names\=, and =\-unset\=
web::param is an accessor to state information from the querystring.
Suppose the querystring is "lang=EN". After web::dispatch has parsed the
querystring, =\web::param lang\= will report =\EN\=. Additionaly,
web::param can manage this data and add, append, and delete parameters as
needed.
==D web::param -names
returns a list of all known keys
==D web::param <key> ?<default>?
returns the value for <key>. Can be a list. In case
that <key> does not exist, return <default>, if it is
given, or an empty string.
==D web::param -count <key>
returns number of items in list of <key>
==D web::param -set <key>
does the same as 'web::param <key>'
==D web::param -set <key> <value> ?<value> ...?
add the parameter <key> to the web::param data.
Any existing parameters with <key> are overwritten
==D web::param -lappend <key> <value> ?<value> ...?
append parameters with the same <key> to the web::param data. In
this case the existing <value> is not overwritten
==D web::param -unset
deletes all parameters from the web::param data
==D web::param -unset <key>
delete a parameter from the web::param data
-- web::formvar --
==D syntax
=|web::formvar|= ?options? ?<key>? ?<value>?\\
Exactly like =\web::param\=
web::formvar is an accessor to HTML <FORM> data. After web::dispatch has
parsed the POST data, you can access all form fields using web::formvar.
-- Examples --
--- ---------------------------------------------------------------------------
web::request CONTENT_LENGTH
==>
web::dispatch -querystring [web::cdurl default] -postdata "" -cmd ""
web::param
==> t cmd
web::param cmd
==> default
web::param -set k v
web::param
==> t cmd k
--- ---------------------------------------------------------------------------
== response data handling ==
webshell can send output to any Tcl channel and to global
variables (=\web::put\=). Optionally, data is scanned for Tcl code before it is
output to a channel (=\web::putx\=).
webshell manages =/response objects/= that are
related to Tcl channels and are identified using the name of the
corresponding Tcl channel. Configuration with =\web::response\=.
-- web::response --
==D Syntax
=|web::response|=\\
=|web::response|= ?option?\\
=|web::response|= ?subcommand? args\\
Subcommands are =|-select|=, =|-set|=, =|-lappend|=,
=|-names|=, =|-count|=, =|-unset|=, =|-reset|=, and =|-resetall|=
Options are =|-sendheader|=, =|-httpresponse|=, and =|-bytessent|=.\\
Selects the default response object and sets and accesses properties
of the response object, and returns the name of the response object.
=\web::response -select <channelName>\= selects <channelName> as new
response object. If the <channelName> is prepended by a #, it refers
to a global variable named <channelName>.
==D web::response
returns the name of the currently selected response object
==D web::response -select ?#?<channel>
makes <channel> the new default response object and returns the
old default response object
==D web::response -set <key> ?<value>?
sets property <key> to <value>, or returns current value if
<value> is omitted.\\
The <keys> are names of HTTP header fields (do not include ':' at
the end of the header field name) and <value> the corresponding
value of the field (like Content-Type) and their values (like
text/html).\\
Example:\\
=\web::response -set Status 200\=
==D web::response -names
returns the list of known keys
==D web::response -count <key>
returns number of items in list of <key>
==D web::response -unset ?<key>?
delete the value of <key>, if <key> is given, or
all keys.
==D web::response -sendheader ?<boolean>?
Sets the sendheader flag which indicates and controls
whether the HTTP headers have been or should be sent.
It is initially set to 1 and set to 0 after the first
call of =\web::put\= or =\web::putx\=. If <boolean> is
omitted, returns the current value.
==D web::response -httpresponse ?<value>?
Sets the HTTP response like "HTTP/1.0 200 OK" for the given
(or default) channel. If no <value> given, returns the the
current HTTP response set. In the case of the Apache module
mod_websh, Apache replaces the protocol "HTTP/??" in the
reponse to "HTTP/1.1"
==D web::response -bytessent
returns the number of bytes that have already been sent to this
channel.
==D web::response -reset
resets the 'sendheader' flag for the channel to true, the HTTP
response to the default "HTTP/?? 200 OK", removes any HTTP headers
set, and resets the names of the query string parameters for the timestamp
and the command to their default values ("t" and "cmd", respectively)
==D web::response -resetall
makes a 'web::response -reset' on all registered channels
-- web::put --
==D Syntax:
=|web::put|= ??#?<channel>? <text>
Send output to a Tcl channel.
No newline is added to output.
-- web::putx --
==D Syntax:
=|web::putx|= ??#?<channel>? <text>
Writes <text> to the specified channel. Code in curly brackets is
eval'd, unless the brackets are escaped by "\". These markup characters
'{...}' can be changed to '<% ... %>' with 'web::config putxmarkup tag'.
-- web::putxfile --
==D Syntax:
=|web::putxfile|= ??#?<channel>? <file> ?<msg>?
As web::putx, but takes input from a file.
Returns 0 on success, 1 otherwise. If an error occurs, an error
message is written to <msg>. If only two arguments are passed, then
<channel> takes precedence.
-- Examples --
--- ---------------------------------------------------------------------------
web::response
==> stdout
web::response -select stderr
==> stdout
web::response
==> stderr
web::response -sendheader
==> 1
web::response -names
==> Content-Type Generator
web::response -set Content-type
==> text/html
web::response -bytessent
==> 0
web::response -lappend "Set-Cookie" "mycookie"
web::put "Hello, world"
==>Content-Type: text/html
Generator: websh 3.0 (c) Netcetera AG, http://netcetera.ch
Set-Cookie: mycookie
Hello, world
--- ---------------------------------------------------------------------------
== logging ==
Logging consists of two parts. =\web::log\= issues a logging message,
while =\web::logfilter\= and =\web::logdest\= determine where to send
a message. webshell uses a two-step filtering. First, webshell
determines whether it should handle a message, or not, using
the filters configured with "web::logfilter". Then, webshell
determines which message is to be sent where, using the filters
configured with =\web::logdest\=.
A filter consists of a tag and a level, separated
by a ".". The tag is free text. Typically, it is the name of the application,
say "foo". Example: "ws3.debug". Levels are, in order:
==* alert
==* error
==* warning
==* info
==* debug
-- web::logdest --
web::logdest add -maxchar 25 -format "%x %X \$l \$m" *.-debug command logTest
==D Syntax:
=|web::logdest|= subcommand ?options? <level> <plugin>\\
Subcommands are: =\add\=, =\delete\=, and =\names\=.\\
Options are: =\-maxchar\=, and =\-format\=.\\
Known plug-ins are: =\file\=, =\syslog\=, =\command\=,
=\channel\=, and =\apache\=. =|Note|=: the plugins may have
indiviudal options (=\-unbuffered)\=, see documentation below.
The format string consits of format specifications for =\fprintf()\=
plus: =\p\= (process id), =\t\= (thread id), =\n\= (log level),
=\f\= (log type), and =\m\= (the message).
-- web::logfilter --
==D Syntax:
=|web::logfilter|= subcommand args\\
Subcommands are: =\add\=, =\delete\=, and =\names\=.
Add a filter to the list.
==D web::logfilter add <level>
add a <level> to the list
==D web::logfilter delete ?<name>?
remove a <name> from list, or remove all filters if <name> is omitted.
==D web::logfilter names
list all filters that have been set
-- web::log --
==D Syntax:
=|web::log|= <level> <msg>
Issue a log message. =/Note/= that, for performance reasons,
variables and command names <msg> will be substituted by the log
module and you should put <msg> in curly braces to prevent Tcl from
substituting the string as well. This ensures that webshell only
spends time on messages which actually pass all filters, and debug
messages that contain variable names and commands will not slow down
the productive system, where no debug messages pass the filters. This
default behaviour can be changed with 'web::config logsubst 0'.
-- log plug-ins --
.. file ..
==D Syntax:
web::logdest add *.-debug =|file|= ?options? <fileName>\\
Option is: =\-unbuffered\=
.. syslog ..
==D Syntax:
web::logdest add *.-debug =|syslog|= <level>\\
See the man page for syslog for levels on your system. Typical: 10.
.. command ..
==D Syntax:
web::logdest add *.-debug =|command|= <cmdName>
.. channel ..
==D Syntax:
web::logdest add *.-debug =|channel|= ?options? <channel>\\
Option is: =\-unbuffered\=
.. apache ..
web::logdest add *.-debug =|apache|=
Available in mod_websh only.
-- Examples --
--- ---------------------------------------------------------------------------
web::logfilter add *.-debug
web::logdest add *.-debug channel stdout
web::log info {websh is cool}
==> 03/01/00 00:00:00 [111] user.info: websh is cool
web::logdest add -format "--> \$m\n" *.-debug channel stdout
web::log info {websh is cool}
==> --> websh is cool
web::logdest add -maxchar 5 *.-debug channel stdout
web::log info {websh is cool}
==> 03/01/00 00:00:00 [111] user.info: websh is cool
--- ---------------------------------------------------------------------------
== context handling ==
-- web::context --
==D Creation
=|web::context|= <name>
Creates a namespace <name> with the following commands:
==D Syntax
=|<name>|=::<subcommand> <args>\\
Subcommands are: =\cset\=, =\cappend\=, =\clappend\=,
=\cget\=, =\cexists\=, =\cunset\=, =\carray\=,
=\cnames\=, and =\dump\=.
Manages data of the context. The subcommands have their
familiar behaviour of the Tcl commands with similar
names.
==D <name>::cset <key> <value>
store <value>
==D <name>::cappend <key> <value> ?<value> ...?
append <value> to existing value for <key>
==D <name>::clappend <key> <value> ?<value> ...?
append <value> to existing list of values for <key>
==D <name>::cget <key> ?<default>?
access the value for key <key>, or return <default>
if <key> does not exist in the context. If <default>
is omitted, an empty string is returned if <key>
is unknown.
==D <name>::cexists <key>
returns true (1) if <key> exists in context, false (0)
otherwise.
==D <name>::cunset <key>
remove <key> from context
==D <name>::carray <option> <key> <arg>
array manipulation as known from the Tcl command
=/array/=
==D <name>::cnames ?<pattern>?
lists existing keys of context matching <pattern>
==D <name>::dump
serialize context
Example:
--- ---------------------------------------------------------------------------
% web::context sc
% sc::cset lang FR
... some code ...
set lang [sc::cget lang EN]
==> FR
--- ---------------------------------------------------------------------------
-- web::filecontext --
==D Creation:
=|web::filecontext|= <name> ?options?\\
Options are: =\-perm\=, =\-path\=, =\-crypt\=,
=\-idgen\=, and =\-attachto\=.
Creates a namespace <name> to manage file-based context data:
==D Syntax
=|<name>|=::<subcommand> <args>\\
Subcommands are: =\cset\=, =\cappend\=, =\clappend\=,
=\cget\=, =\cexists\=, =\cunset\=, =\carray\=,
=\cnames\=, =\init\=, =\new\=, =\commit\=, =\invalidate\=, and =\id\=.
Manages file-based context data. The subcommands have their familiar
behaviour of the Tcl commands with similar names. Please refer to the
section =\context management\= for a description of the commands
=\cset\=, =\cappend\=, =\clappend\=, =\cget\=, =\cexists\=,
=\cunset\=, =\carray\=, and =\cnames\=.
==D <name>::init ?<id>?
load an existing session context with id <id>, or create a new one,
if possible. Automation depends on the settings of the actual
context manager settings, see below.\\
If you specify an <id>, you must decide when to create
a new file and when to use the old one, if any, by yourself.
==D <name>::new ?<id>?
create a new session context. Automation depends on the settings of the
actual context manager settings, see below.
==D <name>::commit
make session context persistent
==D <name>::id
return id of session
==D <name>::invalidate
delete session in memory and on file system
Options:
==D web::filecontext <name> -perm <perm>
set the file permissions of the session context files
<perm> is an unix-like octal value like 0644.
==D web::filecontext <name> -path <path>
specify where to store session context files and
how to name them. Suppose that the session id is 99.
=/-path [file join .. data s%d.dat]/= would then
cause filecontext to save the session context
as =\../data/s99.dat\=
==D web::filecontext <name> -crypt <boolean>
Flag to turn crypting of session context on and off.
Default is on.
==D web::filecontext <name> -idgen <idgen>
Sets command <idgen> to find a new session id. See doc of
=/web::filecounter/= below for an implementation
provided with webshell.\\
<idgen> is used in case that no <id> argument
has been passed to =/init/= or =/new/=.
==D web::filecontext <name> -attachto <idparam>
Use =\web::param <idparam>\= to access current session id.
This option is only used if =/init/= has been called
without <id> argument.\\
webshell passes session ids from one HTML request to
the next using the querystring (this is one reason why
the querystring is encrypted). After web::dispatch
has parsed the querystring, web::param will report the
current session id, if any. =/Note/= that you can
maintain several sessions in parallel, and attach every
session to its own <idparam>.\\
Using =/web::dispatch -track/= further automates the
passing of session ids from request to request.
=|Note:|= Whenever you create a new file-based context, the context is
initialized and you loose whatever information that you might have
stored in the context before you initialized it as a file-based
session context.
-- web::cookiecontext --
==D Creation:
=|web::cookiecontext|= <name> ?options?\\
Options are: =\-expires\=, =\-path\=, =\-domain\=,
=\-secure\=, =\-crypt\=, and =\-channel\=.
Creates a namespace <name> to manage cookie-based context data:
==D Syntax
=|<name>|=::<subcommand> <args>\\
Subcommands are: =\cset\=, =\cappend\=, =\clappend\=,
=\cget\=, =\cexists\=, =\cunset\=, =\carray\=,
=\cnames\=, =\init\=, =\new\=, =\commit\=, =\invalidate\=, and =\id\=.
==D <name>::init ?<id>?
load an existing session context (cookie must have been sent by the
client).
==D <name>::new ?<id>?
create a new session context.
==D <name>::commit
send a cookie
==D <name>::id
return id of session
==D <name>::invalidate
delete session in memory and on client side
Options:
==D web::cookiecontext <name> -expires <time>
set the expiration date of the cookie. Possible values for <time>
are =/day/= (lifetime: one day), =/week/=, =/today/=, =/seconds/=
(time in seconds since 1-1-1970) or =/date-string/=.
==D web::cookiecontext <name> -path <path>
set the =/path/= property of the cookie
==D web::cookiecontext <name> -domain <domain>
set the =/domain/= property of the cookie
==D web::cookiecontext <name> -secure <boolean>
set the =/secure/= property of the cookie
==D web::cookiecontext <name> -crypt <boolean>
Flag to turn crypting of cookie context on and off.
Default is on.
==D web::cookiecontext <name> -channel <channelName>
The response object to send the cookie to (see also
=\web::response\=).
Because cookies are client-based, in principle no id is
needed. webshell uses <id> to name the cookie, however, and the
=\new\=, =\init\=, and =\load\= commands still require the <id>
argument. (fixme: any changes?) Please note that property settings
of a cookie context can only be changed =|before|= anything is output
on the respective channel.
-- web::filecounter --
This is a numeric sequence-number generator which stores its state
in a file. Basic usage:
==D Creation:
web::filecounter <name> ?<options>?\\
Options are: =\-filename\=, =\-min\=, =\-max\=, =\-seed\=, =\-incr\=, =\-wrap\=
==D -filename <filename>
uses <filename> to store the current value
==D -min <value>
uses this value as a minimum, if wrap is true
==D -max <value>
uses this value as a maximum, if wrap is true
==D -seed <value>
if persistant file does not yet exists, use this value as a starting point
==D -incr <value>
uses this value as an increment for each 'nextval'
==D -wrap <boolean>
indicates whether this counter should wrap around its values
After creation, a new command <name> is registered with the following two
subcommands:
==D <name> nextval
return the next value
==D <name> curval
return the current value, that is, the value that
the last call to "nextval" reported (as opposed
to the current value in the file)
-- Examples --
--- ---------------------------------------------------------------------------
web::filecounter handleName -filename "test.dat"
==> from now on, use handleName <curval|nextval>
web::filecounter handleName -filename "test.dat" \
-min 1 -max 10 -seed 1 -incr 2 -wrap 1
--- ---------------------------------------------------------------------------
== file handling and file I/O ==
-- web::include --
==D Syntax:
web_include <fileName> ?<msg>?
If the file <fileName> exists, it is sourced (must be a
script). Otherwise if the library fileName+"shared lib extension"
exists, it is loaded (must be a shared library). Returns 0 on success,
1 otherwise. If an error occurs, an error message is written to <msg>.
-- web::readfile --
==D Syntax:
web::readfile <file> <varName> <msg>
<file> is read and written to <varName>. Returns 0 on success, 1
otherwise. If an error occurs, an error message is written to the
variable <msg>.
-- web::lockfile and web::unlockfile --
==D Syntax:
=|web::lockfile|= <fh>\\
=|web::unlockfile|= <fh>
Interface to lockf(). lockf() works best on local filesystems. Please
read the documentation of lockf on your system to learn about the
problems and limitations of file locking. Note that web::lockfile also
performs a seek() and resets the file cursor to the beginning of the
file.
=/Note/= that the file needs to be open for writing.
-- web::truncatefile --
==D Syntax:
=|web::truncatefile|= <fh>
Interface to truncate(). Truncates a file based on the file handle,
while Tcl's file commands are based on file names. This is used to
truncate a file while holding the lock.
-- Examples --
--- ---------------------------------------------------------------------------
set fh [open [web::tempfile] w]
web::lockfile $fh
puts $fh foo
web::unlockfile $fh
close $fh
--- ---------------------------------------------------------------------------
== data encryption ==
Encrypt (=\web::encrypt\=) and decrypt (=\web::decrypt\=) data. By
default, the built-in, weak encryption is used. encryption is
extensible by plug-Ins. The encryption module tries all plug-Ins from
a list until the first plug-In was able to en-/decrypt the input. See
=\web::config\= for the configuration of the plug-Ins to be used.
-- web::encrypt --
==D Syntax:
=|web::encrypt|= <data>
Returns encrypted data.
-- web::decrypt --
==D Syntax:
=|web::decrypt|= <data>
Returns decrypted data.
Examples:
--- ---------------------------------------------------------------------------
% web::encrypt "Hello, world!"
==> XDaL9T6OqaqUXVJVKDAKQU
% web::decrypt [web::encrypt "Hello, world!"]
==> Hello, world!
--- ---------------------------------------------------------------------------
-- encryption plug-in D --
.. web::encryptd ..
By default, webshell uses this plug-In for weak data encryption for
encryption (=\web::encryptd\=) and decryption (=\web::decryptd\=).
The encryption key is managed with =\web::crpytdkey\=.
==D Syntax:
=|web::encryptd|= <data>
Returns encrypted data.
.. web::decryptd ..
==D Syntax:
=|web::decryptd|= <data>
Returns decrypted data.
.. web::cryptdkey ..
==D Syntax:
=|web::cryptdkey|= ?<key>?
Sets the new key for encryption. If no argument is given, resets to
the default key. This command does not return the currently active
key, in difference to other configuration commands of webshell 3.
Commands:
==D web::encryptd <message>
encrypts <message>
==D web::decryptd <message>
decrypts <message>
==D web::cryptdkey ?<key>?
-- encryption plug-in interface --
=/For plug-in developers only/=\\
The encryption plug-in is required to implement the interface
described below:
==* web::yourencrypt accepts one argument
web::yourencrypt takes a string as input and generates a string which
must be URI compliant
==* web::yourdecrypt accepts one argument
web::yourdecrypt takes a string as input and returns a string
==* symmetry: =/$in == [web::yourdecrypt [web::yourencrypt $in]]/=
==* error messaging:
=/TCL_OK/= for success\\
=/TCL_ERROR/= for any error during en-/decryption\\
=/TCL_CONTINUE/= for unknown encryption type (pass on to next method)
== uri-/html- en-/decoding ==
-- web::htmlify --
-- web::dehtmlify --
-- web::uriencode --
-- web::uridecode --
==* =|web::htmlify|= ?-options? <text>\\
Options is: =\-numeric\=.\\
Return HTML-compliant <text> with HTML encoded entities in mnemonic form
(e.g. ä) or - with option -numeric - numeric form (e.g. ä)
==* =|web::dehtmlify|= <text>\\
Remove all HTML-specifics of <text>
==* =|web::uriencode|= <text>\\
Return URI-compliant <text>.
==* =|web::uridecode|= <text>\\
Decode URI-compliant <text>.
-- Examples --
--- ---------------------------------------------------------------------------
% web::htmlify �
==> ä
% web::htmlify -numeric �
==> ä
% web::dehtmlify ä
==> �
% web::uriencode "Hello, world!"
==> Hello,+world%21
% web::uridecode %21
==> !
--- ---------------------------------------------------------------------------
== inter-process/-system communication ==
Send to and receive from sockets.
-- web::send --
==D Syntax:
=|web::send|= <channel> <cmdNr> <message> ??#?<flags>?
Send the command <cmdNr> and the message <message> to channel
<channelName> using the flags <flags>. The command numbers are
application specific. If #<flags> is used, flags is the numeric
(integer) representation of the flags is to be set. If the # is
omitted, <flags> is a list of symbolic flags. Currently, there is only
one flag: "multiple" or "noflush" with the same meaning,
indicating that there is more to follow and no automatic flush on the
channel should be done.
-- web::recv --
==D Syntax:
=|web::recv|= <channel> <cmdVarName> <msgVarName> <flagVarName>
Receives a message from <channelName>. The other arguments are the
names of the corresponding variables which will contain the message.
The flags are returned numeric. (To handle these flags, use the
web::msgflag function).
-- web::msgflag --
==D Syntax:
=|web::msgflag|= ?<flags>? ?<testflags>?
Set or test flags.
==D web::msgflag
returns a list of all known message flags
==D web::msgflag <flags>
returns the integer representation of the flags listed in <flags>
==D web::msgflag <flags> <testflags>
returns 1, if the flags in <testflags> are set in <flags>
-- Examples --
== Apache module specific commands ==
-- web::initializer --
==D Syntax:
=|web::initializer|= <code>
This code is executed only when a new interpreter is created. Note
that the "main" Webshell script can =\source\= several modules which
each call their initialization code.
-- web::finalizer --
==D Syntax:
=|web::finalizer|= <code>
Register code to be exectuted when the interpreter for this
Webshell script is deleted. =|web::dofinalize|= will then call
each <code> block that has been registered, starting with the
most recently added <code>.
-- web::dofinalize --
==D Syntax:
=|web::dofinalize|=
Execute finalizer code that has been registerd using
=|web::finalizer|=, starting with the most recently added <code>.
-- web::maineval --
==D Syntax:
=|web::maineval|= <code>
Execute code in the "main" interpreter of mod_websh.
-- web::interpclasscfg --
==D Syntax:
=|web::interpclasscfg|= <classid> property ?value?\\
Properties are: =\maxrequests\=, =\maxttl\=, =\maxidletime\=
Set or accesses properties of the interpreter class <classid>.
==D web::interpclasscfg <classid> maxrequests ?<value>?
gets or sets the maximum number of requests interpreters of this
class should handle. If <value> is 0, handle an unlimited number
of requests. Default: 0
==D web::interpclasscfg <classid> maxttl ?<value>?
gets or sets the maximum number of seconds interpreters of this
class should live. If <value> is 0, it lives forever. Default: 0
==D web::interpclasscfg <classid> maxidletime ?<value>?
gets or sets the maximum number of seconds interpreters of this
class should live beeing idle. If <value> is 0, no idle timeout is
assumed. Default: 0
-- web::interpcfg --
==D Syntax:
=|web::interpcfg|= ?property? ?value?\\
Properties are: =\numreq\=, =\retire\=, =\starttime\=, =\lastusedtime\=
Sets or accesses properties of the current interpreter.
==D web::interpcfg
returns <classid> of current interpreter.
==D web::interpcfg numreq
gets the number of requests handled by this interpreter
==D web::interpcfg retire ?<boolean>?
gets or sets the flag indicating this interpreter should be removed
after handling the current request
==D web::interpcfg starttime
returns the time in seconds since the epoch, this interpreter was started
==D web::interpcfg lastusedtime
returns the time in seconds since the epoch, this interpreter was last used
(starttime in case of first request).
== misc commands ==
-- web::match --
==D Syntax:
web::match <result> <listToBeSearched> <searchFor>
In case <searchFor> exists in <listToBeSearched>, web::match returns
<result>, otherwise an empty string.
For websh2 wizards:\\
wpp_isselected v1 v2 would now be:
web::match "selected" v1 v2
web::match treats v1 as a list. Thus, =/web::match "ok" {tv dvd vcr} dvd/=
will return =/ok/=.
-- web::tempfile --
Returns a unique name of a temporary file. The maximum of guaranteed
unique names per application is system dependent. This command just
returns the name of a file. It is the programmers job to handle the
file, for example to open it. Note that webshell keeps an internal
list of all file names generated with web::tempfile and will attempt
to delete all files when the interpreter dies.
=|Note|=: We try to keep this quick reference up-to-date and hope that
it will be useful. We do not guarantee that it is suitable for any
particular purpose whatsoever. The authors accept no liability in
respect to this information or its use.
The original version of this document can always be found
at =(http://websh.com)=.
---
$Id: quickref.syp,v 1.1 2002/05/08 10:31:09 davidw Exp $
---
1.1 tcl-site/websh/quickref.ws3
Index: quickref.ws3
===================================================================
## www.websh.com/quickref.html
## nca-115-2
## $Id: quickref.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 2
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 2 "quick reference"}
<tr valign="top">
{navbar_docu 2}
<td width="610">
{includeFile quickref.pre}
</td>
</tr>
</table>
}
finishPage 2
1.1 tcl-site/websh/quickref.xml
Index: quickref.xml
===================================================================
<?xml version="1.0" encoding="iso-8859-1"?>
<!--
$Id: quickref.xml,v 1.1 2002/05/08 10:31:09 davidw Exp $
-->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://infoplaza.netcetera.ch/dtd/docbook/docbookx-4.1.2/docbookx.dtd">
<book lang="en">
<title>themas</title>
<subtitle>The Netcetera Manual of Style</subtitle>
<bookinfo>
<abstract>
<para>themas, the Netcetera Manual of Style is a collection of
information regarding the software engineering process at
Netcetera.</para>
</abstract>
</bookinfo>
<chapter lang="en">
<title>quick ref</title>
<section id="general_remarks">
<title>general remarks</title>
<para>
webshell 3.0 embeds a Tcl 8.3 interpreter, and all Tcl 8.3 commands
are available, too.
Typically, webshell commands have the following syntax:
<emphasis>web::acommand ?options? ?subcommands ? ?arguments?</emphasis>.
Options start with a dash ("-"). As usual, dash-dash ("--") indicates
the "end-of-options". Thus, <emphasis>web::acommand -o1 a1 -- -o2</emphasis>
takes "-o2" as the first argument.
</para><para>
In difference to the normal "set" behaviour of tcl and webshell,
configuration commands of webshell normally return the previously
used value when a new value is set.
</para><para>
In addition to the examples given here you might find
<ulink url="http://websh.com/examples.html">http://websh.com/examples.html</ulink> a usefull source of information.
</para>
</section>
<section id="configuration">
<title>configuration</title>
<para>
</para>
</section>
<section id="web::config">
<title>web::config</title>
<para>
<variablelist>
<varlistentry>
<term>syntax</term>
<listitem>
<para>
<emphasis>web::config</emphasis> <key> ?<value>?</para><para>
<key>: <emphasis>uploadfilesize</emphasis>, <emphasis>cmdparam</emphasis>, <emphasis>timeparam</emphasis>,
<emphasis>logsubst</emphasis>, <emphasis>putxmarkup</emphasis>, <emphasis>version</emphasis>, <emphasis>copyright</emphasis>,
<emphasis>encryptchain</emphasis>, and <emphasis>decryptchain</emphasis></para><para>
If <value> is ommitted, the current value of <key> is returned.
</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist>
<varlistentry>
<term>uploadfilesize ?<size>?</term>
<listitem>
<para>
Sets the maximum number of bytes allowed to be uploaded.
Default: 0.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>cmdparam ?<name>?</term>
<listitem>
<para>
Name of the parameter to store reference to a web::command command
in the URL. Default: "cmd".
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>timeparam ?<name>?</term>
<listitem>
<para>
Name of the parameter to store reference to the timestamp
in the URL. Default: "t".
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>logsubst ?<boolean>?</term>
<listitem>
<para>
Turns substitution of log messages on or off. Default: on.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>putxmarkup ?brace|tag?</term>
<listitem>
<para>
Sets the markup characters for sections to be eval'd in web::putx
and web::putxfile commands to either curly braces ({ ... }) or
special tags (<% ... %>). Please note that when using the tags <%%>,
they cannot be nested. Default: brace.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>version</term>
<listitem>
<para>
Returns the version info string
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>copyright</term>
<listitem>
<para>
Returns a copyright message string
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>encryptchain <list></term>
<listitem>
<para>
defines which commands should be tried, in sequence, to encrypt
a message. Default: "web::encryptd"
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>decryptchain <list></term>
<listitem>
<para>
defines which commands should be tried, in sequence, to decrypt
a message. Default: "web::decryptd"
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="Examples0">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
web::config decryptchain
==> web::encryptd
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="command_dispatching_and_session_management">
<title>command dispatching and session management</title>
<para>
webshell provides a command dispatching mechanism to produce, for
example, different HTML pages within one application. The name of the
command to be used is encoded in the querystring (see <literal remap="tt">web::cmdurl</literal>
for details on how to produce such querystrings). Command dispatching
is initiated with the command <literal remap="tt">web::dispatch</literal>. Commands are defined
with <literal remap="tt">web::command</literal>.
</para>
</section>
<section id="web::command">
<title>web::command</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::command</emphasis> ?<cmdName>? <cmdBody>
</para>
</listitem>
</varlistentry>
</variablelist>
Registers <cmdBody> as <cmdName>. If <cmdName> is
omitted, "default" is used.
</para>
</section>
<section id="web::getcommand">
<title>web::getcommand</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::getcommand</emphasis> ?<cmdName>?
</para>
</listitem>
</varlistentry>
</variablelist>
Retrieves the body of the command <commandName> or of the command "default"
if <cmdName> is omitted.
</para>
</section>
<section id="web::cmdurl">
<title>web::cmdurl</title>
<para>
<variablelist>
<varlistentry>
<term>syntax</term>
<listitem>
<para>
<emphasis>web::cmdurl</emphasis> ?options? <cmdName> ?<key-value-list>?</para><para>
<emphasis>web::cmdurl</emphasis> ?options? <cmdName> <k1> <v1> ... <kN> <vN></para><para>
Options are: <literal remap="tt">-notimestamp</literal>, and \=-urlformat\=
</para>
</listitem>
</varlistentry>
</variablelist>
Generate URLs including querystring. By default, URLs are
self-referencing, but the exact output is subject to configuration. The
querystring is encrypted, using the encryption method specified by
configuration (see <literal remap="tt">web::config</literal>). If <cmdName> is "", no command parameter
is produced in the query string.
<variablelist>
<varlistentry>
<term>-notimestamp</term>
<listitem>
<para>
do not add a timestamp to the URL
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-urlformat <list></term>
<listitem>
<para>
specify what items will be used to format just this URL.
Default is: <literal remap="tt">{scriptname pathinfo querystring}</literal></para><para>
Use <literal remap="tt">web::cmdurlcfg</literal> to define the url format for all
URLs produced by <literal remap="tt">web::cmdurl</literal> in one request.</para><para>
<variablelist>
<varlistentry>
<term>scheme</term>
<listitem>
<para>
include the protocol, only "http" and "https" are currently supported
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>host</term>
<listitem>
<para>
include the host name, e.g. "websh.com"
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>port</term>
<listitem>
<para>
include the port, e.g. "80"</para><para>
Trying to set this item without host will throw
an error
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>scriptname</term>
<listitem>
<para>
include scriptname, e.g. "/cgi-bin/orderbooks"
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>pathinfo</term>
<listitem>
<para>
include pathinfo, e.g. "/merchants/shop1"
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>querystring</term>
<listitem>
<para>
include the querystring, e.g. "select=download"
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
Note that there are two more commands that control
the output of <literal
remap="tt">web::cmdurl</literal>: <literal
remap="tt">web::config cmdparam</literal> and
<literal remap="tt">web::config
timeparam</literal>.
</para>
</note>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="Examples2">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
web::cmdurl -notimestamp -urlformat [list scheme host scriptname pathinfo querystring] "test"
==> http://websh.com/bin/returnmail/member?XDZuRD2rnsfHjFH
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="web::cmdurlcfg">
<title>web::cmdurlcfg</title>
<para>
<variablelist>
<varlistentry>
<term>syntax</term>
<listitem>
<para>
<emphasis>web::cmdurlcfg</emphasis> ?options? ?<key>? ?<value>?</para><para>
Exactly like <literal remap="tt">web::param</literal></para><para>
<emphasis>web::cmdurlcfg</emphasis> option ?<value>?</para><para>
Options are <emphasis>-scheme</emphasis>, <emphasis>-host</emphasis>, <emphasis>-port</emphasis>,
<emphasis>-scriptname</emphasis>, <emphasis>-pathinfo</emphasis>, <emphasis>-querystring</emphasis>, <emphasis>-urlformat</emphasis></para><para>
If <value> is omitted, the current value is returned.
Otherwise, the <value> is stored.
</para>
</listitem>
</varlistentry>
</variablelist>
Configuration for web::cmdurl. This command serves two purposes:
<orderedlist>
<listitem><para>management of static parameters</para></listitem>
<listitem><para>configuration for <literal remap="tt">web::cmdurl</literal></para></listitem>
</orderedlist>
</para>
</section>
<section id="management_of_static_parameters">
<title>management of static parameters</title>
<para>
In order to set, retrieve, append or unset static parameters,
use the syntax of the <literal remap="tt">web::param</literal> command, for example:
<variablelist>
<varlistentry>
<term>web::cmdurlcfg -set <key> <value></term>
<listitem>
<para>
add the static parameter <key>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::cmdurlcfg</term>
<listitem>
<para>
returns a list of all known static parameters
</para>
</listitem>
</varlistentry>
</variablelist>
</para><para>
<emphasis>Important</emphasis>: <literal remap="tt">web::cmdurl</literal> compares every key from the static
parameters (see <literal remap="tt">web::cmdurlcfg</literal>) against the keys from the command
line. The static parameter is only used if there is no parameter given
on the command line.
</para>
</section>
<section id="configuration_for_web_cmdurl">
<title>configuration for <literal remap="tt">web::cmdurl</literal></title>
<para>
<variablelist>
<varlistentry>
<term>web::cmdurlcfg -protocol ?<value>?</term>
<listitem>
<para>
protocol to be used. Default: http.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::cmdurlcfg -servername ?<value>?</term>
<listitem>
<para>
server name to be used. Default: taken from request.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::cmdurlcfg -port </term>
<listitem>
<para>
port number to be used. Default: 80.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-scriptname</term>
<listitem>
<para>
name of CGI executable. Default: taken from request.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-pathinfo</term>
<listitem>
<para>
path info (path after scriptname). Default: taken from request.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-urlformat <list></term>
<listitem>
<para>
changes the urlformat permanently. See web::cmdurl for the
description of this option
</para>
</listitem>
</varlistentry>
</variablelist>
In all cases, "web::cmdurlcfg -option <value>" sets the value of
the given option and returns the value that was used before the change,
while "web::cmdurlcfg -option" returns the current value. If no value
has been set using web::cmdurlcfg, but is requested for the URL
generation, the value from the request will be used. This value,
however, can not be retrieved using web::cmdurlcfg.
</para><para>
Note that setting a value to an empty string amounts to "unset".
<emphasis>Note also</emphasis>: web::cmdurl compares every key from the static
parameters see -->(web::cmdurlcfg) against the keys from the command
line. The static parameter is only used if there is no such parameter on
the command line.
</para>
</section>
<section id="Examples3">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
% web::cmdurl
==> ?XD8Fseb6tjYQsBUWZ9
% web::cmdurlcfg -scriptname bin/test_script
% web::cmdurl
==> bin/test_script?XD8Fseb6tjYRl1M9Fl
% web::cmdurlcfg -scriptname ""
% web::cmdurl
==> ?XD8Fseb6tjYQsBUWZ9
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="web::dispatch">
<title>web::dispatch</title>
<para>
<variablelist>
<varlistentry>
<term>syntax</term>
<listitem>
<para>
<emphasis>web::dispatch</emphasis> ?options?</para><para>
Options are: <literal remap="tt">-cmd</literal>, <literal remap="tt">-querystring</literal>, <literal remap="tt">-postdata</literal>,
<literal remap="tt">-track</literal> and <literal remap="tt">-hook</literal>
</para>
</listitem>
</varlistentry>
</variablelist>
Parse information and call a command.
<variablelist>
<varlistentry>
<term>web::dispatch -cmd <cmdName></term>
<listitem>
<para>
switch into command <cmdName>. If <cmdName> is an empty string,
no command is called. By default, <cmdName> is taken from
the querystring.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::dispatch -querystring <string></term>
<listitem>
<para>
parse <string> as querystring. If <string> is an empty string,
querystring parsing is turned off. By default, querystring is
taken from the request data (CGI environment or apache module
request object).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::dispatch -postdata <string> ?<content_type>?</term>
<listitem>
<para>
parse <string> as POST data input with type <content_type>.
<content_type> can be <literal remap="tt">application/x-www-form-urlencoded</literal> or
<literal remap="tt">multipart/form-data; boundary=xxx</literal>. In the second case,
<content-type> must specify the boundary as well. By default,
POST data is taken from the request data.</para><para>
If <string> is an empty string, postdata parsing is turned off.</para><para>
Default for <content_type> is "application/x-www-form-urlencoded"
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::dispatch -postdata <channelName> <content_length> <content_type></term>
<listitem>
<para>
As above, but reads the POST data from channel <channelName>.</para><para>
Use the keyword <literal remap="tt">end</literal> for <content_length> to indicate that
websh should read all content.</para><para>
Examples for <content_type> include:
<itemizedlist>
<listitem><para><literal remap="tt">multipart/form-data; boundary=xxxx</literal></para></listitem>
<listitem><para><literal remap="tt">application/x-www-form-urlencoded</literal></para></listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::dispatch -track <paramKeyList></term>
<listitem>
<para>
Track a parameter: register it as "static" for the generation of
URLs with web::cmdurl. Thus, each parameter with the key in
<paramKeyList> will be repeated in every URL generated with
web::cmdurl. See the documentation of web::cmdurl for details.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::dispatch -hook <code></term>
<listitem>
<para>
Causes web::dispatch to eval <code> just before the command (from
any source) is evaluated. When <code> is evaluated, the full
request information has been parsed. That is, web::param,
web::formvar etc. will have up-to-date information when
<code> is evaluated.
</para>
</listitem>
</varlistentry>
</variablelist>
<emphasis>Note</emphasis> that, if no command is passed to web::dispatch either in the
querystring or with the -cmd option, web::dispatch will call the
command "default".
</para>
</section>
<section id="Examples4">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
set tst {puts "On the hook"}
web::command acmd { puts "this is acmd" }
web::dispatch -cmd acmd -querystring "" -postdata ""
==> this is acmd
web::dispatch -cmd acmd -querystring "" -postdata "" -hook $tst
==> On the hook
==> this is acmd
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="session_management">
<title>session management</title>
<para>
Webshell session management consits of two parts:
<itemizedlist>
<listitem><para>session id tracking</para></listitem>
<listitem><para>session context management</para></listitem>
</itemizedlist>
</para>
<para>
Session context managers are described in detail below
(<emphasis>web::filecontext</emphasis>,
<emphasis>web::cookiecontext</emphasis>). Session id tracking
is managed by <literal remap="tt">web::dispatch
-track</literal>. The two parts are connected with the
<emphasis>-attachto</emphasis> option of the session context
manager. The control is as follows:
</para>
<para>
<itemizedlist>
<listitem>
<para>
a user uses the Webshell script for the first
time.<literal remap="tt">web::dispatch -track</literal>
will not see any session id, and, consequently, not set
the static parameter <literal remap="tt">id</literal>.
</para>
</listitem>
<listitem>
<para>
Within the application, the session is initialized using
<literal
remap="tt"><mgr>::init</literal>. <literal
remap="tt">init</literal> will find no static parameter
<literal remap="tt">id</literal> (which has been
specified at creation time of the session manager using
the <literal remap="tt">-attachto</literal> option).
Now, it tries to create a new session id. This will be
possible if a session id generator has been specified
when the manager was created using the <literal
remap="tt">-idgen</literal> option. From now, on the
session id will be a static parameter, and will
therefore be present in every URL generated with
<emphasis>web::cmdurl</emphasis>
</para>
</listitem>
<listitem>
<para>
The next time the user visits the Webshell application
using one of these URLs,
<emphasis>web::dispatch</emphasis> will detect the
session id, and =|<mgr>::init= will directly load
the corresponding session context without generating a
new session id.
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section id="Examples5">
<title>Examples</title>
<para>
See <ulink url="http://websh.com/examples.html">http://websh.com/examples.html</ulink> for several sample
application demonstrating the session management of Webshell.
</para>
</section>
<section id="request_data_handling">
<title>request data handling</title>
<para>
</para>
</section>
<section id="web::request">
<title>web::request</title>
<para>
<variablelist>
<varlistentry>
<term>syntax</term>
<listitem>
<para>
<emphasis>web::request</emphasis> ?options? ?<key>? ?<value> ...?</para><para>
<emphasis>web::request</emphasis> ?<key>? ?<default>?</para><para>
Options are: <literal remap="tt">-count</literal>, <literal remap="tt">-set</literal>, <literal remap="tt">-lappend</literal>, <literal remap="tt">-names</literal>, <literal remap="tt">-unset</literal>, <literal remap="tt">-reset</literal>
and <literal remap="tt">-channel</literal> fixme: gibt es -channel noch?
</para>
</listitem>
</varlistentry>
</variablelist>
web::request is an accessor to CGI related information.
<variablelist>
<varlistentry>
<term>web::request</term>
<listitem>
<para>
returns a list of all known keys
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::request <key> ?<default>?</term>
<listitem>
<para>
returns the value for <key>. Can be a list. In case
that <key> does not exist, return <default>, if it is
given, or an empty string.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::request -count <key></term>
<listitem>
<para>
returns number of items in list for <key>; returns 0 if
<key> does not exist
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::request -set <key></term>
<listitem>
<para>
does the same as 'web::request <key>'
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::request -set <key> <value> ?<value> ...?</term>
<listitem>
<para>
adds the parameter <key> to the web::request data.
Any existing parameters with <key> are overwritten
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::request -lappend <key> <value> ?<value> ...?</term>
<listitem>
<para>
append parameters with the same <key> to the web::request data. In
this case the existing <value> is not overwritten
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::request -unset</term>
<listitem>
<para>
deletes all parameters from the web::request data
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::request -unset <key></term>
<listitem>
<para>
deletes a parameter from the web::request data
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::request -reset</term>
<listitem>
<para>
deletes all parameters from the web::request data (like 'web::request -unset'),
removes all static parameters (like 'web::cmdurlcfg -unset'), all form variables
(like 'web::formvar -unset'), all query string parameters (like 'web::param -unset'),
and all temporary files created by HTTP form upload
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::request -channel</term>
<listitem>
<para>
fixme: what does it?
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="web::param">
<title>web::param</title>
<para>
<variablelist>
<varlistentry>
<term>syntax</term>
<listitem>
<para>
<emphasis>web::param</emphasis> ?options? ?<key>? ?<value> ...?</para><para>
Options are: <literal remap="tt">-count</literal>, <literal remap="tt">-set</literal>, <literal remap="tt">-lappend</literal>, <literal remap="tt">-names</literal>, and <literal remap="tt">-unset</literal>
</para>
</listitem>
</varlistentry>
</variablelist>
web::param is an accessor to state information from the querystring.
Suppose the querystring is "lang=EN". After web::dispatch has parsed the
querystring, <literal remap="tt">web::param lang</literal> will report <literal remap="tt">EN</literal>. Additionaly,
web::param can manage this data and add, append, and delete parameters as
needed.
<variablelist>
<varlistentry>
<term>web::param -names</term>
<listitem>
<para>
returns a list of all known keys
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::param <key> ?<default>?</term>
<listitem>
<para>
returns the value for <key>. Can be a list. In case
that <key> does not exist, return <default>, if it is
given, or an empty string.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::param -count <key></term>
<listitem>
<para>
returns number of items in list of <key>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::param -set <key></term>
<listitem>
<para>
does the same as 'web::param <key>'
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::param -set <key> <value> ?<value> ...?</term>
<listitem>
<para>
add the parameter <key> to the web::param data.
Any existing parameters with <key> are overwritten
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::param -lappend <key> <value> ?<value> ...?</term>
<listitem>
<para>
append parameters with the same <key> to the web::param data. In
this case the existing <value> is not overwritten
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::param -unset</term>
<listitem>
<para>
deletes all parameters from the web::param data
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::param -unset <key></term>
<listitem>
<para>
delete a parameter from the web::param data
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="web::formvar">
<title>web::formvar</title>
<para>
<variablelist>
<varlistentry>
<term>syntax</term>
<listitem>
<para>
<emphasis>web::formvar</emphasis> ?options? ?<key>? ?<value>?</para><para>
Exactly like <literal remap="tt">web::param</literal>
</para>
</listitem>
</varlistentry>
</variablelist>
web::formvar is an accessor to HTML <FORM> data. After web::dispatch has
parsed the POST data, you can access all form fields using web::formvar.
</para>
</section>
<section id="Examples6">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
web::request CONTENT_LENGTH
==>
web::dispatch -querystring [web::cdurl default] -postdata "" -cmd ""
web::param
==> t cmd
web::param cmd
==> default
web::param -set k v
web::param
==> t cmd k
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="response_data_handling">
<title>response data handling</title>
<para>
webshell can send output to any Tcl channel and to global
variables (<literal remap="tt">web::put</literal>). Optionally, data is scanned for Tcl code before it is
output to a channel (<literal remap="tt">web::putx</literal>).
webshell manages <emphasis>response objects</emphasis> that are
related to Tcl channels and are identified using the name of the
corresponding Tcl channel. Configuration with <literal remap="tt">web::response</literal>.
</para>
</section>
<section id="web::response">
<title>web::response</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax</term>
<listitem>
<para>
<emphasis>web::response</emphasis></para><para>
<emphasis>web::response</emphasis> ?option?</para><para>
<emphasis>web::response</emphasis> ?subcommand? args</para><para>
Subcommands are <emphasis>-select</emphasis>, <emphasis>-set</emphasis>, <emphasis>-lappend</emphasis>,
<emphasis>-names</emphasis>, <emphasis>-count</emphasis>, <emphasis>-unset</emphasis>, <emphasis>-reset</emphasis>, and <emphasis>-resetall</emphasis>
Options are <emphasis>-sendheader</emphasis>, <emphasis>-httpresponse</emphasis>, and <emphasis>-bytessent</emphasis>.</para><para>
</para>
</listitem>
</varlistentry>
</variablelist>
Selects the default response object and sets and accesses properties
of the response object, and returns the name of the response object.
</para><para>
<literal remap="tt">web::response -select <channelName></literal> selects <channelName> as new
response object. If the <channelName> is prepended by a #, it refers
to a global variable named <channelName>.
<variablelist>
<varlistentry>
<term>web::response</term>
<listitem>
<para>
returns the name of the currently selected response object
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -select ?#?<channel></term>
<listitem>
<para>
makes <channel> the new default response object and returns the
old default response object
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -set <key> ?<value>?</term>
<listitem>
<para>
sets property <key> to <value>, or returns current value if
<value> is omitted.\\
The <keys> are names of HTTP header fields (do not include ':' at
the end of the header field name) and <value> the corresponding
value of the field (like Content-Type) and their values (like
text/html).</para><para>
Example:</para><para>
<literal remap="tt">web::response -set Status 200</literal>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -names</term>
<listitem>
<para>
returns the list of known keys
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -count <key></term>
<listitem>
<para>
returns number of items in list of <key>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -unset ?<key>?</term>
<listitem>
<para>
delete the value of <key>, if <key> is given, or
all keys.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -sendheader ?<boolean>?</term>
<listitem>
<para>
Sets the sendheader flag which indicates and controls
whether the HTTP headers have been or should be sent.
It is initially set to 1 and set to 0 after the first
call of <literal remap="tt">web::put</literal> or <literal remap="tt">web::putx</literal>. If <boolean> is
omitted, returns the current value.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -httpresponse ?<value>?</term>
<listitem>
<para>
Sets the HTTP response like "HTTP/1.0 200 OK" for the given
(or default) channel. If no <value> given, returns the the
current HTTP response set. In the case of the Apache module
mod_websh, Apache replaces the protocol "HTTP/??" in the
reponse to "HTTP/1.1"
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -bytessent</term>
<listitem>
<para>
returns the number of bytes that have already been sent to this
channel.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -reset</term>
<listitem>
<para>
resets the 'sendheader' flag for the channel to true, the HTTP
response to the default "HTTP/?? 200 OK", removes any HTTP headers
set, and resets the names of the query string parameters for the timestamp
and the command to their default values ("t" and "cmd", respectively)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::response -resetall</term>
<listitem>
<para>
makes a 'web::response -reset' on all registered channels
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="web::put">
<title>web::put</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::put</emphasis> ??#?<channel>? <text>
</para>
</listitem>
</varlistentry>
</variablelist>
Send output to a Tcl channel.
No newline is added to output.
</para>
</section>
<section id="web::putx">
<title>web::putx</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::putx</emphasis> ??#?<channel>? <text>
</para>
</listitem>
</varlistentry>
</variablelist>
Writes <text> to the specified channel. Code in curly brackets is
eval'd, unless the brackets are escaped by "\". These markup characters
'{...}' can be changed to '<% ... %>' with 'web::config putxmarkup tag'.
</para><para>
</para>
</section>
<section id="web::putxfile">
<title>web::putxfile</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::putxfile</emphasis> ??#?<channel>? <file> ?<msg>?
</para>
</listitem>
</varlistentry>
</variablelist>
As web::putx, but takes input from a file.
Returns 0 on success, 1 otherwise. If an error occurs, an error
message is written to <msg>. If only two arguments are passed, then
<channel> takes precedence.
</para><para>
</para>
</section>
<section id="Examples7">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
web::response
==> stdout
web::response -select stderr
==> stdout
web::response
==> stderr
web::response -sendheader
==> 1
web::response -names
==> Content-Type Generator
web::response -set Content-type
==> text/html
web::response -bytessent
==> 0
web::response -lappend "Set-Cookie" "mycookie"
web::put "Hello, world"
==>Content-Type: text/html
Generator: websh 3.0 (c) Netcetera AG, http://netcetera.ch
Set-Cookie: mycookie
Hello, world
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="logging">
<title>logging</title>
<para>
Logging consists of two parts. <literal remap="tt">web::log</literal> issues a logging message,
while <literal remap="tt">web::logfilter</literal> and <literal remap="tt">web::logdest</literal> determine where to send
a message. webshell uses a two-step filtering. First, webshell
determines whether it should handle a message, or not, using
the filters configured with "web::logfilter". Then, webshell
determines which message is to be sent where, using the filters
configured with <literal remap="tt">web::logdest</literal>.
A filter consists of a tag and a level, separated
by a ".". The tag is free text. Typically, it is the name of the application,
say "foo". Example: "ws3.debug". Levels are, in order:
<itemizedlist>
<listitem><para>alert</para></listitem>
<listitem><para>error</para></listitem>
<listitem><para>warning</para></listitem>
<listitem><para>info</para></listitem>
<listitem><para>debug</para></listitem>
</itemizedlist>
</para>
</section>
<section id="web::logdest">
<title>web::logdest</title>
<para>
web::logdest add -maxchar 25 -format "%x %X \$l \$m" *.-debug command logTest
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::logdest</emphasis> subcommand ?options? <level> <plugin></para><para>
Subcommands are: <literal remap="tt">add</literal>, <literal remap="tt">delete</literal>, and <literal remap="tt">names</literal>.</para><para>
Options are: <literal remap="tt">-maxchar</literal>, and <literal remap="tt">-format</literal>.</para><para>
Known plug-ins are: <literal remap="tt">file</literal>, <literal remap="tt">syslog</literal>, <literal remap="tt">command</literal>,
<literal remap="tt">channel</literal>, and <literal remap="tt">apache</literal>. <emphasis>Note</emphasis>: the plugins may have
indiviudal options (<literal remap="tt">-unbuffered)</literal>, see documentation below.
</para>
</listitem>
</varlistentry>
</variablelist>
The format string consits of format specifications for <literal remap="tt">fprintf()</literal>
plus: <literal remap="tt">p</literal> (process id), <literal remap="tt">t</literal> (thread id), <literal remap="tt">n</literal> (log level),
<literal remap="tt">f</literal> (log type), and <literal remap="tt">m</literal> (the message).
</para>
</section>
<section id="web::logfilter">
<title>web::logfilter</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::logfilter</emphasis> subcommand args</para><para>
Subcommands are: <literal remap="tt">add</literal>, <literal remap="tt">delete</literal>, and <literal remap="tt">names</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
Add a filter to the list.
<variablelist>
<varlistentry>
<term>web::logfilter add <level></term>
<listitem>
<para>
add a <level> to the list
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::logfilter delete ?<name>?</term>
<listitem>
<para>
remove a <name> from list, or remove all filters if <name> is omitted.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::logfilter names</term>
<listitem>
<para>
list all filters that have been set
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="web::log">
<title>web::log</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::log</emphasis> <level> <msg>
</para>
</listitem>
</varlistentry>
</variablelist>
Issue a log message. <emphasis>Note</emphasis> that, for performance reasons,
variables and command names <msg> will be substituted by the log
module and you should put <msg> in curly braces to prevent Tcl from
substituting the string as well. This ensures that webshell only
spends time on messages which actually pass all filters, and debug
messages that contain variable names and commands will not slow down
the productive system, where no debug messages pass the filters. This
default behaviour can be changed with 'web::config logsubst 0'.
</para><para>
</para>
</section>
<section id="log_plug-ins">
<title>log plug-ins</title>
<para>
</para>
</section>
<section id="file">
<title>file</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
web::logdest add *.-debug <emphasis>file</emphasis> ?options? <fileName></para><para>
Option is: <literal remap="tt">-unbuffered</literal>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="syslog">
<title>syslog</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
web::logdest add *.-debug <emphasis>syslog</emphasis> <level></para><para>
</para>
</listitem>
</varlistentry>
</variablelist>
See the man page for syslog for levels on your system. Typical: 10.
</para>
</section>
<section id="command">
<title>command</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
web::logdest add *.-debug <emphasis>command</emphasis> <cmdName>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="channel">
<title>channel</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
web::logdest add *.-debug <emphasis>channel</emphasis> ?options? <channel></para><para>
Option is: <literal remap="tt">-unbuffered</literal>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="apache">
<title>apache</title>
<para>
web::logdest add *.-debug <emphasis>apache</emphasis>
Available in mod_websh only.
</para>
</section>
<section id="Examples8">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
web::logfilter add *.-debug
web::logdest add *.-debug channel stdout
web::log info {websh is cool}
==> 03/01/00 00:00:00 [111] user.info: websh is cool
web::logdest add -format "--> \$m\n" *.-debug channel stdout
web::log info {websh is cool}
==> --> websh is cool
web::logdest add -maxchar 5 *.-debug channel stdout
web::log info {websh is cool}
==> 03/01/00 00:00:00 [111] user.info: websh is cool
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="context_handling">
<title>context handling</title>
<para>
</para>
</section>
<section id="web::context">
<title>web::context</title>
<para>
<variablelist>
<varlistentry>
<term>Creation </term>
<listitem>
<para>
<emphasis>web::context</emphasis> <name>
</para>
</listitem>
</varlistentry>
</variablelist>
Creates a namespace <name> with the following commands:
<variablelist>
<varlistentry>
<term>Syntax</term>
<listitem>
<para>
<emphasis><name></emphasis>::<subcommand> <args></para><para>
Subcommands are: <literal remap="tt">cset</literal>, <literal remap="tt">cappend</literal>, <literal remap="tt">clappend</literal>,
<literal remap="tt">cget</literal>, <literal remap="tt">cexists</literal>, <literal remap="tt">cunset</literal>, <literal remap="tt">carray</literal>,
<literal remap="tt">cnames</literal>, and <literal remap="tt">dump</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
Manages data of the context. The subcommands have their
familiar behaviour of the Tcl commands with similar
names.
<variablelist>
<varlistentry>
<term><name>::cset <key> <value></term>
<listitem>
<para>
store <value>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::cappend <key> <value> ?<value> ...?</term>
<listitem>
<para>
append <value> to existing value for <key>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::clappend <key> <value> ?<value> ...?</term>
<listitem>
<para>
append <value> to existing list of values for <key>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::cget <key> ?<default>?</term>
<listitem>
<para>
access the value for key <key>, or return <default>
if <key> does not exist in the context. If <default>
is omitted, an empty string is returned if <key>
is unknown.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::cexists <key></term>
<listitem>
<para>
returns true (1) if <key> exists in context, false (0)
otherwise.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::cunset <key></term>
<listitem>
<para>
remove <key> from context
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::carray <option> <key> <arg></term>
<listitem>
<para>
array manipulation as known from the Tcl command
<emphasis>array</emphasis>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::cnames ?<pattern>?</term>
<listitem>
<para>
lists existing keys of context matching <pattern>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::dump</term>
<listitem>
<para>
serialize context
</para>
</listitem>
</varlistentry>
</variablelist>
Example:
<programlisting>
---------------------------------------------------------------------------
% web::context sc
% sc::cset lang FR
... some code ...
set lang [sc::cget lang EN]
==> FR
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="web::filecontext">
<title>web::filecontext</title>
<para>
<variablelist>
<varlistentry>
<term>Creation:</term>
<listitem>
<para>
<emphasis>web::filecontext</emphasis> <name> ?options?</para><para>
Options are: <literal remap="tt">-perm</literal>, <literal remap="tt">-path</literal>, <literal remap="tt">-crypt</literal>,
<literal remap="tt">-idgen</literal>, and <literal remap="tt">-attachto</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
Creates a namespace <name> to manage file-based context data:
<variablelist>
<varlistentry>
<term>Syntax</term>
<listitem>
<para>
<emphasis><name></emphasis>::<subcommand> <args></para><para>
Subcommands are: <literal remap="tt">cset</literal>, <literal remap="tt">cappend</literal>, <literal remap="tt">clappend</literal>,
<literal remap="tt">cget</literal>, <literal remap="tt">cexists</literal>, <literal remap="tt">cunset</literal>, <literal remap="tt">carray</literal>,
<literal remap="tt">cnames</literal>, <literal remap="tt">init</literal>, <literal remap="tt">new</literal>, <literal remap="tt">commit</literal>, <literal remap="tt">invalidate</literal>, and <literal remap="tt">id</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
Manages file-based context data. The subcommands have their familiar
behaviour of the Tcl commands with similar names. Please refer to the
section <literal remap="tt">context management</literal> for a description of the commands
<literal remap="tt">cset</literal>, <literal remap="tt">cappend</literal>, <literal remap="tt">clappend</literal>, <literal remap="tt">cget</literal>, <literal remap="tt">cexists</literal>,
<literal remap="tt">cunset</literal>, <literal remap="tt">carray</literal>, and <literal remap="tt">cnames</literal>.
<variablelist>
<varlistentry>
<term><name>::init ?<id>?</term>
<listitem>
<para>
load an existing session context with id <id>, or create a new one,
if possible. Automation depends on the settings of the actual
context manager settings, see below.</para><para>
If you specify an <id>, you must decide when to create
a new file and when to use the old one, if any, by yourself.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::new ?<id>?</term>
<listitem>
<para>
create a new session context. Automation depends on the settings of the
actual context manager settings, see below.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::commit</term>
<listitem>
<para>
make session context persistent
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::id</term>
<listitem>
<para>
return id of session
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::invalidate</term>
<listitem>
<para>
delete session in memory and on file system
</para>
</listitem>
</varlistentry>
</variablelist>
Options:
<variablelist>
<varlistentry>
<term>web::filecontext <name> -perm <perm></term>
<listitem>
<para>
set the file permissions of the session context files
<perm> is an unix-like octal value like 0644.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::filecontext <name> -path <path></term>
<listitem>
<para>
specify where to store session context files and
how to name them. Suppose that the session id is 99.
<emphasis>-path [file join .. data s%d.dat]</emphasis> would then
cause filecontext to save the session context
as <literal remap="tt">../data/s99.dat</literal>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::filecontext <name> -crypt <boolean></term>
<listitem>
<para>
Flag to turn crypting of session context on and off.
Default is on.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::filecontext <name> -idgen <idgen></term>
<listitem>
<para>
Sets command <idgen> to find a new session id. See doc of
<emphasis>web::filecounter</emphasis> below for an implementation
provided with webshell.</para><para>
<idgen> is used in case that no <id> argument
has been passed to <emphasis>init</emphasis> or <emphasis>new</emphasis>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::filecontext <name> -attachto <idparam></term>
<listitem>
<para>
Use <literal remap="tt">web::param <idparam></literal> to access current session id.
This option is only used if <emphasis>init</emphasis> has been called
without <id> argument.</para><para>
webshell passes session ids from one HTML request to
the next using the querystring (this is one reason why
the querystring is encrypted). After web::dispatch
has parsed the querystring, web::param will report the
current session id, if any. <emphasis>Note</emphasis> that you can
maintain several sessions in parallel, and attach every
session to its own <idparam>.</para><para>
Using <emphasis>web::dispatch -track</emphasis> further automates the
passing of session ids from request to request.
</para>
</listitem>
</varlistentry>
</variablelist>
<emphasis>Note:</emphasis> Whenever you create a new file-based context, the context is
initialized and you loose whatever information that you might have
stored in the context before you initialized it as a file-based
session context.
</para>
</section>
<section id="web::cookiecontext">
<title>web::cookiecontext</title>
<para>
<variablelist>
<varlistentry>
<term>Creation:</term>
<listitem>
<para>
<emphasis>web::cookiecontext</emphasis> <name> ?options?</para><para>
Options are: <literal remap="tt">-expires</literal>, <literal remap="tt">-path</literal>, <literal remap="tt">-domain</literal>,
<literal remap="tt">-secure</literal>, <literal remap="tt">-crypt</literal>, and <literal remap="tt">-channel</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
Creates a namespace <name> to manage cookie-based context data:
<variablelist>
<varlistentry>
<term>Syntax</term>
<listitem>
<para>
<emphasis><name></emphasis>::<subcommand> <args></para><para>
Subcommands are: <literal remap="tt">cset</literal>, <literal remap="tt">cappend</literal>, <literal remap="tt">clappend</literal>,
<literal remap="tt">cget</literal>, <literal remap="tt">cexists</literal>, <literal remap="tt">cunset</literal>, <literal remap="tt">carray</literal>,
<literal remap="tt">cnames</literal>, <literal remap="tt">init</literal>, <literal remap="tt">new</literal>, <literal remap="tt">commit</literal>, <literal remap="tt">invalidate</literal>, and <literal remap="tt">id</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
<variablelist>
<varlistentry>
<term><name>::init ?<id>?</term>
<listitem>
<para>
load an existing session context (cookie must have been sent by the
client).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::new ?<id>?</term>
<listitem>
<para>
create a new session context.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::commit</term>
<listitem>
<para>
send a cookie
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::id</term>
<listitem>
<para>
return id of session
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name>::invalidate</term>
<listitem>
<para>
delete session in memory and on client side
</para>
</listitem>
</varlistentry>
</variablelist>
Options:
<variablelist>
<varlistentry>
<term>web::cookiecontext <name> -expires <time></term>
<listitem>
<para>
set the expiration date of the cookie. Possible values for <time>
are <emphasis>day</emphasis> (lifetime: one day), <emphasis>week</emphasis>, <emphasis>today</emphasis>, <emphasis>seconds</emphasis>
(time in seconds since 1-1-1970) or <emphasis>date-string</emphasis>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::cookiecontext <name> -path <path></term>
<listitem>
<para>
set the <emphasis>path</emphasis> property of the cookie
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::cookiecontext <name> -domain <domain></term>
<listitem>
<para>
set the <emphasis>domain</emphasis> property of the cookie
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::cookiecontext <name> -secure <boolean></term>
<listitem>
<para>
set the <emphasis>secure</emphasis> property of the cookie
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::cookiecontext <name> -crypt <boolean></term>
<listitem>
<para>
Flag to turn crypting of cookie context on and off.
Default is on.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::cookiecontext <name> -channel <channelName></term>
<listitem>
<para>
The response object to send the cookie to (see also
<literal remap="tt">web::response</literal>).
</para>
</listitem>
</varlistentry>
</variablelist>
Because cookies are client-based, in principle no id is
needed. webshell uses <id> to name the cookie, however, and the
<literal remap="tt">new</literal>, <literal remap="tt">init</literal>, and <literal remap="tt">load</literal> commands still require the <id>
argument. (fixme: any changes?) Please note that property settings
of a cookie context can only be changed <emphasis>before</emphasis> anything is output
on the respective channel.
</para>
</section>
<section id="web::filecounter">
<title>web::filecounter</title>
<para>
This is a numeric sequence-number generator which stores its state
in a file. Basic usage:
<variablelist>
<varlistentry>
<term>Creation:</term>
<listitem>
<para>
web::filecounter <name> ?<options>?</para><para>
Options are: <literal remap="tt">-filename</literal>, <literal remap="tt">-min</literal>, <literal remap="tt">-max</literal>, <literal remap="tt">-seed</literal>, <literal remap="tt">-incr</literal>, <literal remap="tt">-wrap</literal>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-filename <filename></term>
<listitem>
<para>
uses <filename> to store the current value
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-min <value></term>
<listitem>
<para>
uses this value as a minimum, if wrap is true
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-max <value></term>
<listitem>
<para>
uses this value as a maximum, if wrap is true
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-seed <value></term>
<listitem>
<para>
if persistant file does not yet exists, use this value as a starting point
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-incr <value></term>
<listitem>
<para>
uses this value as an increment for each 'nextval'
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-wrap <boolean></term>
<listitem>
<para>
indicates whether this counter should wrap around its values
</para>
</listitem>
</varlistentry>
</variablelist>
After creation, a new command <name> is registered with the following two
subcommands:
<variablelist>
<varlistentry>
<term><name> nextval</term>
<listitem>
<para>
return the next value
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><name> curval</term>
<listitem>
<para>
return the current value, that is, the value that
the last call to "nextval" reported (as opposed
to the current value in the file)
</para>
</listitem>
</varlistentry>
</variablelist>
</para><para>
</para>
</section>
<section id="Examples9">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
web::filecounter handleName -filename "test.dat"
==> from now on, use handleName <curval|nextval>
web::filecounter handleName -filename "test.dat" \
-min 1 -max 10 -seed 1 -incr 2 -wrap 1
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="file_handling_and_file_IO">
<title>file handling and file I/O</title>
<para>
</para>
</section>
<section id="web::include">
<title>web::include</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
web_include <fileName> ?<msg>?
</para>
</listitem>
</varlistentry>
</variablelist>
If the file <fileName> exists, it is sourced (must be a
script). Otherwise if the library fileName+"shared lib extension"
exists, it is loaded (must be a shared library). Returns 0 on success,
1 otherwise. If an error occurs, an error message is written to <msg>.
</para>
</section>
<section id="web::readfile">
<title>web::readfile</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
web::readfile <file> <varName> <msg>
</para>
</listitem>
</varlistentry>
</variablelist>
<file> is read and written to <varName>. Returns 0 on success, 1
otherwise. If an error occurs, an error message is written to the
variable <msg>.
</para>
</section>
<section id="web::lockfile_and_web::unlockfile">
<title>web::lockfile and web::unlockfile</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::lockfile</emphasis> <fh></para><para>
<emphasis>web::unlockfile</emphasis> <fh>
</para>
</listitem>
</varlistentry>
</variablelist>
Interface to lockf(). lockf() works best on local filesystems. Please
read the documentation of lockf on your system to learn about the
problems and limitations of file locking. Note that web::lockfile also
performs a seek() and resets the file cursor to the beginning of the
file.
<emphasis>Note</emphasis> that the file needs to be open for writing.
</para>
</section>
<section id="web::truncatefile">
<title>web::truncatefile</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::truncatefile</emphasis> <fh>
</para>
</listitem>
</varlistentry>
</variablelist>
Interface to truncate(). Truncates a file based on the file handle,
while Tcl's file commands are based on file names. This is used to
truncate a file while holding the lock.
</para>
</section>
<section id="Examples10">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
set fh [open [web::tempfile] w]
web::lockfile $fh
puts $fh foo
web::unlockfile $fh
close $fh
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="data_encryption">
<title>data encryption</title>
<para>
Encrypt (<literal remap="tt">web::encrypt</literal>) and decrypt (<literal remap="tt">web::decrypt</literal>) data. By
default, the built-in, weak encryption is used. encryption is
extensible by plug-Ins. The encryption module tries all plug-Ins from
a list until the first plug-In was able to en-/decrypt the input. See
<literal remap="tt">web::config</literal> for the configuration of the plug-Ins to be used.
</para>
</section>
<section id="web::encrypt">
<title>web::encrypt</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::encrypt</emphasis> <data>
</para>
</listitem>
</varlistentry>
</variablelist>
Returns encrypted data.
</para>
</section>
<section id="web::decrypt">
<title>web::decrypt</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::decrypt</emphasis> <data>
</para>
</listitem>
</varlistentry>
</variablelist>
Returns decrypted data.
Examples:
<programlisting>
---------------------------------------------------------------------------
% web::encrypt "Hello, world!"
==> XDaL9T6OqaqUXVJVKDAKQU
% web::decrypt [web::encrypt "Hello, world!"]
==> Hello, world!
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="encryption_plug-in_D">
<title>encryption plug-in D</title>
<para>
</para>
</section>
<section id="web::encryptd">
<title>web::encryptd</title>
<para>
By default, webshell uses this plug-In for weak data encryption for
encryption (<literal remap="tt">web::encryptd</literal>) and decryption (<literal remap="tt">web::decryptd</literal>).
The encryption key is managed with <literal remap="tt">web::crpytdkey</literal>.
</para><para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::encryptd</emphasis> <data>
</para>
</listitem>
</varlistentry>
</variablelist>
Returns encrypted data.
</para>
</section>
<section id="web::decryptd">
<title>web::decryptd</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::decryptd</emphasis> <data>
</para>
</listitem>
</varlistentry>
</variablelist>
Returns decrypted data.
</para>
</section>
<section id="web::cryptdkey">
<title>web::cryptdkey</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::cryptdkey</emphasis> ?<key>?
</para>
</listitem>
</varlistentry>
</variablelist>
Sets the new key for encryption. If no argument is given, resets to
the default key. This command does not return the currently active
key, in difference to other configuration commands of webshell 3.
Commands:
<variablelist>
<varlistentry>
<term>web::encryptd <message></term>
<listitem>
<para>
encrypts <message>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::decryptd <message></term>
<listitem>
<para>
decrypts <message>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::cryptdkey ?<key>?</term>
<listitem>
<para>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="encryption_plug-in_interface_">
<title>encryption plug-in interface </title>
<para>
<emphasis>For plug-in developers only</emphasis>
</para>
<para>
The encryption plug-in is required to implement the interface
described below:
<itemizedlist>
<listitem>
<para>
web::yourencrypt accepts one argument web::yourencrypt
takes a string as input and generates a string which
must be URI compliant
</para>
</listitem>
<listitem>
<para>
web::yourdecrypt accepts one argument web::yourdecrypt
takes a string as input and returns a string
</para>
</listitem>
<listitem>
<para>symmetry: <emphasis>$in ==
[web::yourdecrypt [web::yourencrypt
$in]]</emphasis>
</para>
</listitem>
<listitem>
<para>
error messaging: <emphasis>TCL_OK</emphasis> for
success. <emphasis>TCL_ERROR</emphasis> for any error
during en-/decryption. <emphasis>TCL_CONTINUE</emphasis>
for unknown encryption type (pass on to next method)
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section id="uri-html-_en-decoding">
<title>uri-/html- en-/decoding</title>
<para>
</para>
<section id="web::htmlify">
<title>web::htmlify</title>
<para>
</para>
</section>
<section id="web::dehtmlify">
<title>web::dehtmlify</title>
<para>
</para>
</section>
<section id="web::uriencode">
<title>web::uriencode</title>
<para>
</para>
</section>
<section id="web::uridecode">
<title>web::uridecode</title>
<para>
<itemizedlist>
<listitem>
<para>
<emphasis>web::htmlify</emphasis> ?-options? <text>
</para>
<para>
Options is: <literal remap="tt">-numeric</literal>.
</para>
<para>
Return HTML-compliant <text> with HTML encoded
entities in mnemonic form (e.g. &auml;) or - with
option -numeric - numeric form (e.g. &#228;)
</para>
</listitem>
<listitem>
<para><emphasis>web::dehtmlify</emphasis> <text>
</para>
<para>
Remove all HTML-specifics of <text>
</para>
</listitem>
<listitem>
<para><emphasis>web::uriencode</emphasis>
<text>
</para>
<para>
Return URI-compliant <text>.
</para>
</listitem>
<listitem>
<para>
<emphasis>web::uridecode</emphasis> <text>
</para>
<para>Decode URI-compliant <text>.
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section id="Examples11">
<title>Examples</title>
<para>
<programlisting>
---------------------------------------------------------------------------
% web::htmlify ä
==> &auml;
% web::htmlify -numeric ä
==> &#228;
% web::dehtmlify &auml;
==> ä
% web::uriencode "Hello, world!"
==> Hello,+world%21
% web::uridecode %21
==> !
---------------------------------------------------------------------------
</programlisting>
</para>
</section>
<section id="inter-process_and_-system_communication">
<title>inter-process/-system communication</title>
<para>
Send to and receive from sockets.
</para>
</section>
<section id="web::send">
<title>web::send</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::send</emphasis> <channel> <cmdNr> <message> ??#?<flags>?
</para>
</listitem>
</varlistentry>
</variablelist>
Send the command <cmdNr> and the message <message> to channel
<channelName> using the flags <flags>. The command numbers are
application specific. If #<flags> is used, flags is the numeric
(integer) representation of the flags is to be set. If the # is
omitted, <flags> is a list of symbolic flags. Currently, there is only
one flag: "multiple" or "noflush" with the same meaning,
indicating that there is more to follow and no automatic flush on the
channel should be done.
</para>
</section>
<section id="web::recv">
<title>web::recv</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::recv</emphasis> <channel> <cmdVarName> <msgVarName> <flagVarName>
</para>
</listitem>
</varlistentry>
</variablelist>
Receives a message from <channelName>. The other arguments are the
names of the corresponding variables which will contain the message.
The flags are returned numeric. (To handle these flags, use the
web::msgflag function).
</para>
</section>
<section id="web::msgflag">
<title>web::msgflag</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::msgflag</emphasis> ?<flags>? ?<testflags>?
</para>
</listitem>
</varlistentry>
</variablelist>
Set or test flags.
<variablelist>
<varlistentry>
<term>web::msgflag</term>
<listitem>
<para>
returns a list of all known message flags
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::msgflag <flags></term>
<listitem>
<para>
returns the integer representation of the flags listed in <flags>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::msgflag <flags> <testflags></term>
<listitem>
<para>
returns 1, if the flags in <testflags> are set in <flags>
</para>
</listitem>
</varlistentry>
</variablelist>
</para><para>
</para>
</section>
<section id="Examples12">
<title>Examples</title>
<para>
</para>
</section>
<section id="Apache_module_specific_commands">
<title>Apache module specific commands</title>
<para>
</para>
</section>
<section id="web::initializer">
<title>web::initializer</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::initializer</emphasis> <code>
</para>
</listitem>
</varlistentry>
</variablelist>
This code is executed only when a new interpreter is created. Note
that the "main" Webshell script can <literal remap="tt">source</literal> several modules which
each call their initialization code.
</para><para>
</para>
</section>
<section id="web::finalizer">
<title>web::finalizer</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::finalizer</emphasis> <code>
</para>
</listitem>
</varlistentry>
</variablelist>
Register code to be exectuted when the interpreter for this
Webshell script is deleted. <emphasis>web::dofinalize</emphasis> will then call
each <code> block that has been registered, starting with the
most recently added <code>.
</para>
</section>
<section id="web::dofinalize">
<title>web::dofinalize</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::dofinalize</emphasis>
</para>
</listitem>
</varlistentry>
</variablelist>
Execute finalizer code that has been registerd using
<emphasis>web::finalizer</emphasis>, starting with the most recently added <code>.
</para>
</section>
<section id="web::maineval">
<title>web::maineval</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::maineval</emphasis> <code>
</para>
</listitem>
</varlistentry>
</variablelist>
Execute code in the "main" interpreter of mod_websh.
</para>
</section>
<section id="web::interpclasscfg">
<title>web::interpclasscfg</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::interpclasscfg</emphasis> <classid> property ?value?</para><para>
Properties are: <literal remap="tt">maxrequests</literal>, <literal remap="tt">maxttl</literal>, <literal remap="tt">maxidletime</literal>
</para>
</listitem>
</varlistentry>
</variablelist>
Set or accesses properties of the interpreter class <classid>.
<variablelist>
<varlistentry>
<term>web::interpclasscfg <classid> maxrequests ?<value>?</term>
<listitem>
<para>
gets or sets the maximum number of requests interpreters of this
class should handle. If <value> is 0, handle an unlimited number
of requests. Default: 0
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::interpclasscfg <classid> maxttl ?<value>?</term>
<listitem>
<para>
gets or sets the maximum number of seconds interpreters of this
class should live. If <value> is 0, it lives forever. Default: 0
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::interpclasscfg <classid> maxidletime ?<value>?</term>
<listitem>
<para>
gets or sets the maximum number of seconds interpreters of this
class should live beeing idle. If <value> is 0, no idle timeout is
assumed. Default: 0
</para>
</listitem>
</varlistentry>
</variablelist>
</para><para>
</para>
</section>
<section id="web::interpcfg">
<title>web::interpcfg</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
<emphasis>web::interpcfg</emphasis> ?property? ?value?</para><para>
Properties are: <literal remap="tt">numreq</literal>, <literal remap="tt">retire</literal>, <literal remap="tt">starttime</literal>, <literal remap="tt">lastusedtime</literal>
</para>
</listitem>
</varlistentry>
</variablelist>
Sets or accesses properties of the current interpreter.
<variablelist>
<varlistentry>
<term>web::interpcfg </term>
<listitem>
<para>
returns <classid> of current interpreter.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::interpcfg numreq</term>
<listitem>
<para>
gets the number of requests handled by this interpreter
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::interpcfg retire ?<boolean>?</term>
<listitem>
<para>
gets or sets the flag indicating this interpreter should be removed
after handling the current request
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::interpcfg starttime</term>
<listitem>
<para>
returns the time in seconds since the epoch, this interpreter was started
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>web::interpcfg lastusedtime</term>
<listitem>
<para>
returns the time in seconds since the epoch, this interpreter was last used
(starttime in case of first request).
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="misc_commands">
<title>misc commands</title>
<para>
</para>
</section>
<section id="web::match">
<title>web::match</title>
<para>
<variablelist>
<varlistentry>
<term>Syntax:</term>
<listitem>
<para>
web::match <result> <listToBeSearched> <searchFor>
</para>
</listitem>
</varlistentry>
</variablelist>
In case <searchFor> exists in <listToBeSearched>, web::match returns
<result>, otherwise an empty string.
</para><para>
For websh2 wizards:</para><para>
wpp_isselected v1 v2 would now be:
web::match "selected" v1 v2
</para><para>
web::match treats v1 as a list. Thus, <emphasis>web::match "ok" {tv dvd vcr} dvd</emphasis>
will return <emphasis>ok</emphasis>.
</para>
</section>
<section id="web::tempfile">
<title>web::tempfile</title>
<para>
Returns a unique name of a temporary file. The maximum of guaranteed
unique names per application is system dependent. This command just
returns the name of a file. It is the programmers job to handle the
file, for example to open it. Note that webshell keeps an internal
list of all file names generated with web::tempfile and will attempt
to delete all files when the interpreter dies.
</para><para>
</para><para>
<emphasis>Note</emphasis>: We try to keep this quick reference up-to-date and hope that
it will be useful. We do not guarantee that it is suitable for any
particular purpose whatsoever. The authors accept no liability in
respect to this information or its use.
</para><para>
The original version of this document can always be found
at <ulink url="http://websh.com">http://websh.com</ulink>.
<programlisting>
$Id: quickref.xml,v 1.1 2002/05/08 10:31:09 davidw Exp $
</programlisting>
</para>
</section>
</section>
</chapter>
</book>
1.1 tcl-site/websh/quickref_head.txt
Index: quickref_head.txt
===================================================================
webshell quick reference
Netcetera AG, Switzerland
Mar 2000
1.1 tcl-site/websh/quickref_pdf_head.html
Index: quickref_pdf_head.html
===================================================================
<html>
<head>
<title>webshell Quick Reference</title>
</head>
<body>
<center><h1>webshell</h1></center>
<center><h2>Quick Reference</h2></center>
<p>
<center>Netcetera AG, Switzerland</center>
<p>
<center>Mar 2000</center>
1.1 tcl-site/websh/resources.ws3
Index: resources.ws3
===================================================================
## www.websh.com/support.html
## nca-115-2
## $Id: resources.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 4
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 4 "resources"}
<tr valign="top">
{navbar_ress 0}
<td width="455">
<img height="160" width="150" src="images/ausschnitt_ressources.gif" vspace="40" align="left" alt="graphics"><br>
On this page, we compile links to webshell related resources and
tools.
<h2>Tcl</h2>
{pageLink www.tcl.tk -pre}
<h2>Tcl and Apache</h2>
{pageLink tcl.apache.org -pre}
<h2>Apache</h2>
{pageLink www.apache.org -pre}
</td>
{newsbar_ress}
</tr>
</table>
}
finishPage 4
1.1 tcl-site/websh/session_form.sample
Index: session_form.sample
===================================================================
#! ../../bin/websh3
# This example shows how persistent sessions can be stored
# on the server.
# It shows two HTML forms which have one input field each.
# You can switch between these two forms using the submit
# buttons. All data given in the form
# Define a memory context to hold some configuration variables.
# The next statement makes a context called 'config' to hold
# these data. It is a cleaner way than making global variables
# because it declares them clearly to be configuration vars.
web::context config
# Now set some configuration variables. Usually put the session
# state files in a directory not accessible through the Web server.
config::cset stateDirectory ./states
# Create a file counter that generates the session ids. We take
# here an easy number generator, which produces sequential numbers
# and stores the actual counter value in a file
web::filecounter idGenerator -filename [file join [config::cget stateDirectory] counter]
# Create a file context named 'state'. The option '-path' defines
# where the session contexts are stored. '-attachto' defines an
# URL parameter name that might contain an existing session.
# (This parameter name could in fact be extracted using
# 'web::param sid' whenever the session is initalized.)
web::filecontext state -path [file join [config::cget stateDirectory] %s] -attachto sid -idgen "idGenerator nextval"
# Make sure the session state directory exists
file mkdir [config::cget stateDirectory]
proc form {page code} {
# Produces a HTML FORM tag. Nested form variables must be output
# in 'code'.
# The 'page' parameter describes the web::command to call when
# the form is submitted.
web::put "<html><head><title>Session Example</title></head>"
web::put "<body bgcolor=\"#FFFFFF\">"
# form starts here
web::put "<form method=\"POST\" action=\"[web::cmdurl $page]\">"
uplevel $code
web::put "</form>"
web::put "</body></html>"
}
proc putErrorMessage {msg} {
# emit an error message in red.
web::put "<p><font color=\"\#ff0000\">[web::htmlify $msg]</font></p>"
}
proc pageOne {{errorMessage ""}} {
# Display page one of our HTML form.
form processPageOne {
if {[string length $errorMessage]} {
putErrorMessage $errorMessage
}
web::put "Numbers only: <input type=\"text\" name=\"a\" value=\"[web::htmlify [state::cget a]]\">"
web::put "<input type=\"submit\" value=\"Page 2\">"
}
}
proc pageTwo {{errorMessage ""}} {
# Display page two of our HTML form.
form processPageTwo {
if {[string length $errorMessage]} {
putErrorMessage $errorMessage
}
web::put "Not empty: <input type=\"text\" name=\"b\" value=\"[web::htmlify [state::cget b]]\">"
web::put "<input type=\"submit\" value=\"Page 1\">"
}
}
proc saveAllFields {} {
# Save all form fields to state context.
# web::formvar without parameters returns a list of HTML form
# variables sent to this script. web::formvar with the name
# of a field returns its value, if the field does not exist
# it returns an empty list (or an optional 2nd parameter 'default
# value').
# For clarity, we do not handle multiple fields with the same
# name correctly here. If a HTML field is given twice or more
# 'web::formvar -count <fieldname>' would give us the field count
# 'web::formvar <fieldname>' returns then a list of n values.
foreach field [web::formvar names] {
state::cset $field [web::formvar $field]
}
}
# Define two dispatched commands to each show one page of the
# (mini) form. The names of theses application commands will
# be used in the submit action of the form with 'web::cmdurl'.
web::command processPageOne {
state::init
if {![regexp {^[0-9]+$} [web::formvar a]]} {
# The input field does not contain only digits, so show page one again
# including an error message.
pageOne "Please enter a number."
} else {
# Everything ok, so save the form field to persistant session
# and proceed with page two.
saveAllFields
state::commit
pageTwo
}
}
web::command processPageTwo {
state::init
if {![string length [web::formvar b]]} {
# The input field is empty, so show page two again
# including an error message.
pageTwo "Please fill in field."
} else {
# Everything ok, so save the form field to persistant session
# and proceed with page one.
saveAllFields
state::commit
pageOne
}
}
# Define the default command to show page one.
web::command default {
# Initialize a fresh state.
state::init
# Show page one initially.
pageOne
}
# Dispatch to one of the web::commands according to a parameter in the
# URL. This parameter was set using 'web::cmdurl' in the FORM tag in
# procedure 'form'.
# At the very beginning we don't have a command in the URL. Then the
# web::command default is called.
# The '-track' parameter is used to take over the URL parameter 'sid'
# from "incoming" URLs to "outgoing" URLs. This parameters holds
# the session id and makes a session survive
# web::dispatch processes the URL - i.e. extracts parameters from the
# URL - and handles HTML form input sent to this script.
web::dispatch -track sid
1.1 tcl-site/websh/subscribe.ws3
Index: subscribe.ws3
===================================================================
## www.websh.com/subscribe.html
## nca-115-2
## $Id: subscribe.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 0
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 3 "webshell newsletter"}
<tr valign="top">
{navbar_null}
<td width="610">
Netcetera edits the webshell newsletter.<br><br>
You can subscribe
for the newsletter by simply adding your e-mail address below.<br>
<FORM action="/bin/mail/websh_news?cmd=subscribe" method="POST">
<INPUT TYPE="TEXT" SIZE="40" MAXLENGTH="60" NAME="user">
<INPUT type="submit" value="subscribe">
</FORM>
<br>
Alternatively, you can subscribe for the newsletter by sending
sending an e-mail to {emailLink majordomo@netcetera.ch}
with <tt>subscribe websh-news</tt> in the body of the message.
<br><br><br>
If at any time you would like to unsubscribe from this newsletter,
you may do so at {pageLink www.websh.com/unsubscribe.html -pre}, or by
sending an e-mail to {emailLink majordomo@netcetera.ch} with
<tt>unsubscribe websh-news</tt> in the body of the message.
<br><br><br>
Thank you for you interest in webshell.
</td>
</tr>
</table>
}
finishPage
1.1 tcl-site/websh/support.ws3
Index: support.ws3
===================================================================
## www.websh.com/support.html
## nca-115-2
## $Id: support.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 3
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 4 "support"}
<tr valign="top">
{navbar_supp}
<td width="455">
<img height="160" width="150" src="images/ausschnitt_support.gif" align="left" alt="graphics">
Netcetera knows that no tool is useful without documentation
and support. That's why we are committed to high-quality support
for webshell. We work hard to keep {pageLink websh.com -pre}
up-to-date with all information you need. Here, you can find
the {pageLink whitepaper.html -show "webshell white paper"} and
the {pageLink quickref.html -show "quick reference"} as well as
a list of {pageLink faq.html -show "frequently asked questions"}.
<br><br>
In addition, we offer <b>free e-mail support</b>. Contact us at
{emailSupportLink}. Our engineers are committed to deliver
high-quality support in no time.
<br><br>
If you consider webshell as a tool for your Internet business,
you might be interested in our <b>maintenance contracts</b>.
Contact us at {emailInfoLink} for a specially tailored offer.
<br><br>
It is our goal to deliver first-quality service. Please feel
free to {emailLink support@websh.com "contact us"} and let us
know what you think about webshell.
</td>
{newsbar_supp}
</tr>
</table>
}
finishPage 3
1.1 tcl-site/websh/syp.tcl
Index: syp.tcl
===================================================================
# -----------------------------------------------------------------------------
# syp - simple yet powerful text processor
# nca-115-2
#
#
# $Id: syp.tcl,v 1.1 2002/05/08 10:31:09 davidw Exp $
# -----------------------------------------------------------------------------
# == what is syp ? ==
#
# -- The idea --
#
# ==* easy to use through implicit syntax (no end tags)
# ==* eye-catching, intuitive syntax
# ==* multi-format output (HTML,txt,rtf,docbook)
#
# -- the tags --
#
# ==* headers:
# ==* == h1 ==
# ==* -- h2 --
# ==* .. h3 ..
# ==* lists:
# ==* ==* unordered list
# ==* ==1 ordered list
# ==* ==D description list
# ==* formatting
# ==* =\=\preformatted\=\=
# ==* =\=|bold|=\=
# ==* =\=/italic/=\=
# ==* misc
# ==* =\=(URL)(text)=\= for links
# ==* =\==Figure==anchor==path\= for figures
# ==* =\==>anchor\= for references
# ==* =\==T\= for tables
# ==* =\--- \= for pre-formatted text
set _syp_mode HTML
set _syp_title TITLE
set _template ""
# ----------------------------------------------------------------------------
# index
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# utils
# ----------------------------------------------------------------------------
proc fputs {str} {
global _ofh
puts $_ofh $str
}
# ----------------------------------------------------------------------------
# tags
# ----------------------------------------------------------------------------
proc boldify {tmp} {return "<b>$tmp</b>"}
proc italicify {tmp} {return "<i>$tmp</i>"}
proc preify {tmp} {return "<tt>$tmp</tt>"}
proc newLine {} {return "<br>"}
proc hrefify {tmp {t2 {}}} {
if { "$t2" == "" } { set t2 $tmp }
return "<a href=\"$tmp\">$t2</a>"
}
# ----------------------------------------------------------------------------
# default processors
# ----------------------------------------------------------------------------
proc procH {type str} {
global _anchors
global _filename
global _linecnt
global _reverseAnchors
set akey [list ${_filename} $str $type ${_linecnt}]
set aname $_anchors($akey)
set tocent $_reverseAnchors($akey)
foreach {fn tit type line h1cnt h2cnt h3cnt} $tocent {}
set cnt $h1cnt
if { $h2cnt > 0 } {
append cnt ".$h2cnt"
}
if { $h3cnt > 0 } {
append cnt ".$h3cnt"
}
fputs "<a name=\"$aname\"><a href=\"\#toc\"><$type>$cnt $str</$type></a>"
}
proc procH1 {str} {
procH h1 $str
}
proc procH2 {str} {
procH h2 $str
}
proc procH3 {str} {
procH h3 $str
}
proc procGenericListStart {type str} {
global _level
global _level_stack
global _state
fputs "<$type>"
incr _level
# puts "DBG genericListStart setting stack($_level) to $type"
set _level_stack($_level) $type
# puts "DBG genericListStart stack now: [array get _level_stack]"
set _state $type
procGenericList $str
}
proc procGenericListEnd {type} {
global _level
global _state
fputs "</$type>"
incr _level -1
if {$_level == 0 } {
set _state ""
}
}
proc procGenericList {str} {
fputs "<li>$str</li>"
}
##
proc procItemizeStart {str} {
return [procGenericListStart ul $str]
}
proc procItemizeEnd {} {
return [procGenericListEnd ul]
}
proc procItemize {str} {
return [procGenericList $str]
}
##
proc procEnumStart {str} {
return [procGenericListStart ol $str]
}
proc procEnumEnd {} {
return [procGenericListEnd ol]
}
proc procEnum {str} {
return [procGenericList $str]
}
##
proc procDescStart {str} {
global _level
global _level_stack
global _state
fputs "<dl>"
incr _level
set _state dl
# puts "DBG descStart setting stack($_level) to dl"
set _level_stack($_level) "dl"
# puts "DBG descStart stack now: [array get _level_stack]"
procDesc $str 1
}
proc procDescEnd {} {
global _level
global _state
fputs "</dl>"
incr _level -1
if {$_level == 0 } {
set _state ""
}
}
proc procDesc {str {isDesc 0}} {
if {$isDesc } {
fputs "<dt>[boldify $str]\n<dd>"
} else {
fputs "$str"
}
}
proc endList {level} {
global _level_stack
# puts "DBG endList stack: [array get _level_stack]"
# puts "DBG endList level: $level"
if { [info exists _level_stack($level)] } {
# puts "DBG endList: found $_level_stack($level)"
switch $_level_stack($level) {
ul {
procItemizeEnd
unset _level_stack($level)
}
ol {
procEnumEnd
unset _level_stack($level)
}
dl {
procDescEnd
unset _level_stack($level)
}
}
} else {
puts "DBG endList: level not found in stack"
}
}
proc procPre {vStr vState} {
upvar $vStr str
upvar $vState state
# puts "DBG procPre - got '$str'"
if {$state == 0} {
fputs "<pre>"
fputs "$str"
set state 1
return
} elseif {$state == 2} {
fputs "$str"
fputs "</pre>"
set state 0
return
}
}
proc procTable {vStr vState} {
global _sypTableRow
upvar $vStr str
upvar $vState state
set cols [split $str {|}]
if {$state == 0} {
# puts "<table border=\"1\">\n"
fputs "<table>"
fputs "<tr>"
foreach col $cols {
fputs " <td>[boldify [string trim $col]]</td>"
}
fputs "</tr>"
set state 1
set _sypTableRow 1
return
} elseif {$state == 2} {
fputs "</table>"
set state 0
return
}
if {$_sypTableRow} {
fputs "<tr bgcolor=\"#99CCCC\">"
set _sypTableRow 0
} else {
fputs "<tr bgcolor=\"#FFFFFF\">"
set _sypTableRow 1
}
foreach col $cols {
set tmp [string trim $col]
if {[string length $tmp] < 1} {
set tmp " "
}
fputs " <td>$tmp</td>"
}
fputs "</tr>"
}
proc procPara {} {
fputs [newLine][newLine]
}
proc findFigRef {id} {
set idx 1
global _sypfig
foreach tmp $_sypfig {
set idinlist [lindex $tmp 0]
if { [string compare $id $idinlist] == 0 } {
return $idx
}
incr idx
}
}
proc procFigRef {id} {
return "Figure [findFigRef $id]"
}
proc procFigure {id url shortdesc caption} {
set tmp [procFigRef $id]
fputs "<center><img src=\"$url\" alt=\"$shortdesc\"></center><br>"
fputs "[boldify $tmp] - $caption <br><br>"
}
proc procIndex {{title "Table of Contents"}} {
global _toc
global _anchors
set isFirst 1
if { [info exists _toc] } {
fputs "<br>"
procH1 $title
foreach item $_toc {
# puts stderr "toc: $item"
# "${fn}:${res}:h1"
foreach {fn tit type line h1cnt h2cnt h3cnt } $item {}
set anchorkey [list $fn $tit $type $line]
# puts "DBG procIndex: key: $anchorkey"
# puts "DBG procIndex: item: $item"
# puts "DBG procIndex: _anchors: [array get _anchors]"
set anc $_anchors($anchorkey)
# puts "DBG anc - $anc"
if { [string equal $type h1] } {
fputs "<br>${h1cnt} <a href=\"\#$anc\"><b>$tit</b></a><br>"
} elseif { [string equal $type h2] } {
fputs " ${h1cnt}.${h2cnt} <a href=\"\#$anc\"><b>$tit</b></a><br>"
} elseif { [string equal $type h3] } {
fputs " ${h1cnt}.${h2cnt}.${h3cnt} <a href=\"\#$anc\"><b>$tit</b></a><br>"
}
}
}
}
proc conformify {in} {
if {[regexp {^%%%(.*)} $in]} {
return $in
} else {
return [web::htmlify -- $in]
}
}
# ----------------------------------------------------------------------------
# override default, if any
# ----------------------------------------------------------------------------
#TBD
# ----------------------------------------------------------------------------
# private methods
# ----------------------------------------------------------------------------
proc isH1 {line vTitle vAnchor} {
upvar $vTitle title
upvar $vAnchor anchor
set title {}
set anchor {}
if {[regexp {^== (.*)} $line dum rest] } {
# puts "DBG starts correctly: rest $rest"
if { [set first [string first " ==" $rest 0]] != -1 } {
incr first -1
set title [string range $rest 0 $first]
incr first 4
set anchor [string range $rest $first end]
return 1
}
}
return 0
}
proc isH2 {line vTitle vAnchor} {
upvar $vTitle title
upvar $vAnchor anchor
set title {}
set anchor {}
if {[regexp {^-- (.*)} $line dum rest] } {
# puts "DBG starts correctly: rest $rest"
if { [set first [string first " --" $rest 0]] != -1 } {
incr first -1
set title [string range $rest 0 $first]
incr first 4
set anchor [string range $rest $first end]
return 1
}
}
return 0
}
proc isH3 {line vTitle vAnchor} {
upvar $vTitle title
upvar $vAnchor anchor
set title {}
set anchor {}
if {[regexp {^\.\. (.*)} $line dum rest] } {
# puts "DBG starts correctly: rest $rest"
if { [set first [string first " .." $rest 0]] != -1 } {
incr first -1
set title [string range $rest 0 $first]
incr first 4
set anchor [string range $rest $first end]
return 1
}
}
return 0
}
# sypsub:
# suppose escape is "|":
# searches for "=|....|=" in txt, calls handler with argument "....", and
# replaces "...." with result from handler
#
# example: "a =|simple | text|= =|with|= a star"
proc sypsub {vTxt escape handler} {
upvar $vTxt txt
set idx 0
set found 0
while { [set first [string first "=$escape" $txt $idx]] != -1 } {
# found one
set idx $first
incr idx
if { [set next [string first "${escape}=" $txt $idx]] != -1 } {
incr next
set start $first
set end $next
incr start 2
incr end -2
set tmp [string range $txt $start $end]
# puts "DBG sypsub - tmp: $tmp"
set tmp [eval [list $handler $tmp]]
set txt [string replace $txt $first $next $tmp]
incr idx [string length $tmp]
set found 1
}
# puts "DBG sypsub - txt now: $txt"
}
return $found
}
# _getNextInputLine
proc _getNextInputLine {fh} {
global _prevLine
global _curLine
global _nextLine
global _linecnt
set _prevLine $_curLine
set _curLine $_nextLine
gets $fh _nextLine
incr _linecnt
#
# make it output compliant (eg htmlify in HTML case)
#
set _nextLine [conformify $_nextLine]
#
# explicit newlines: "some text\\"
#
if { [regsub -all {\\\\$} $_curLine [newLine] tmp] } {
set _curLine $tmp
}
#
# text marked for bold: =*bold*=
#
sypsub _curLine "|" boldify
#
# text marked as pre-formatted: =%pre%=
#
sypsub _curLine "\\" preify
#
# text marked as italic: =/italic/=
#
sypsub _curLine "/" italicify
#
# an explicit link w/o text: "=(http://websh.com)="
#
if { [regsub -all {\=\(([^\)]+)\)\=} $_curLine \
"[hrefify \\1]" tmp] } {
set _curLine $tmp
}
#
# an explicit link: "=(http://websh.com)(the cool websh site)="
#
if { [regsub -all {\=\(([^\)]+)\)\(([^\)]+)\)\=} $_curLine \
"[hrefify \\1 \\2]" tmp] } {
set _curLine $tmp
}
}
# _firstScan -- build list of figures and references
proc _firstScan {fn} {
global _prevLine
global _curLine
global _prevLine
global _anchors
global _toc
global _linecnt
global _sypfig
global _split_level
global _split_first
global _split_last
global _reverseAnchors
set _prevLine ""
set _curLine ""
set _nextLine ""
set _linecnt 0
set _doProcess 1
set mySplitCnt 0
set fh [open $fn "r"]
## first line
if {[eof $fh] == 0} {gets $fh ::_nextLine}
set h1cnt 0
set h2cnt 0
set h3cnt 0
while {[eof $fh] == 0 && $_doProcess} {
_getNextInputLine $fh
set tLine $_curLine
# gets $fh tLine
if { [regexp {^%%%STOPPROCESSINGHERE} $_curLine dum res] } {
set _doProcess 0
continue
} elseif {[regexp {^==Figure==([^=]*)==([^=]*)={0,2}(.*)} $tLine dum id url alt]
!= 0 } {
# puts stderr "DBG -- found $tLine"
lappend _sypfig [list $id $url $alt]
} elseif {[isH1 $tLine res aname] } {
incr h1cnt
set h2cnt 0
set h3cnt 0
if { ![string length $aname] } {
set aname $_linecnt
}
if { $_split_level == 1 } {
incr mySplitCnt
set _split_last $mySplitCnt
set aname "[splitFileName $mySplitCnt]\#${aname}"
}
set anchorkey [list ${fn} ${res} h1 ${_linecnt}]
set tocent [list ${fn} ${res} h1 ${_linecnt} $h1cnt $h2cnt $h3cnt]
set _anchors($anchorkey) $aname
set _reverseAnchors($anchorkey) $tocent
lappend _toc $tocent
} elseif {[isH2 $tLine res aname] } {
incr h2cnt
set h3cnt 0
if { ![string length $aname] } {
set aname $_linecnt
}
set anchorkey [list ${fn} ${res} h2 ${_linecnt}]
set tocent [list ${fn} ${res} h2 ${_linecnt} $h1cnt $h2cnt $h3cnt]
set _anchors($anchorkey) $aname
set _reverseAnchors($anchorkey) $tocent
lappend _toc $tocent
} elseif {[isH3 $tLine res aname] } {
incr h3cnt
set anchorkey [list ${fn} ${res} h3 ${_linecnt}]
set tocent [list ${fn} ${res} h3 ${_linecnt} $h1cnt $h2cnt $h3cnt]
set _anchors($anchorkey) $aname
set _reverseAnchors($anchorkey) $tocent
lappend _toc $tocent
} elseif { [regexp {^%%%TOC *(.*)} $_curLine dum res] } {
incr h1cnt
set h2cnt 0
set h3cnt 0
set anchor toc
if { [string length $res] } {
set title $res
} else {
set title "Table of Contents"
}
set anchorkey [list ${fn} ${title} h1 ${_linecnt}]
set tocent [list ${fn} ${title} h1 ${_linecnt} $h1cnt $h2cnt $h3cnt]
set _anchors($anchorkey) $anchor
set _reverseAnchors($anchorkey) $tocent
lappend _toc $tocent
} elseif { [regexp {^%%%SPLIT *(.*)} $_curLine dum res] && $_split_level } {
incr mySplitCnt
set _split_last $mySplitCnt
}
}
close $fh
incr _split_last
}
# _mainScan -- process line by line
proc _mainScan {fn} {
global _prevLine
global _curLine
global _nextLine
global _linecnt
global _syp_mode
global _syp_title
global _template
global _anchors
global _toc
global _state
global _level
global _split_level
global _cur_h1
set stateInItemize 0
set stateInEnum 0
set stateInDesc 0
set stateInPre 0
set stateIsContinuation 0
set stateInTable 0
set _prevLine ""
set _curLine ""
set _nextLine ""
set _linecnt 0
set _doProcess 1
set fh [open $fn "r"]
## first line
if {[eof $fh] == 0} {gets $fh ::_nextLine}
while {[eof $fh] == 0 && $_doProcess} {
_getNextInputLine $fh
# puts "DBG cur: $_curLine"
if { [regexp {^%%%STOPPROCESSINGHERE} $_curLine dum res] } {
set _doProcess 0
continue
}
## search and replace reference to figure
##[==ws3ov==]
if {[regexp {\[==([^=]*)==\]} $_curLine dum res] != 0 } {
set tmp [procFigRef $res]
regsub {\[==[^=]*==\]} $_curLine $tmp _curLine
}
## continuation
## paragraph
if {[string equal $_prevLine ""] && [string equal $_curLine ""]} {
procPara
continue
}
## pre-processed (do not change)
if {[regexp {^%%%([^ ]+) *(.*)} $_curLine dum mode res] != 0 } {
if { [string equal $_syp_mode $mode] } {
## HTML
fputs $res
} elseif { [string equal $mode "TOC"] } {
if { [string length $res] } {
procIndex $res
} else {
procIndex
}
} elseif { [string equal $mode "SPLIT"] && $_split_level} {
closeOutputFile
openNextOutputFile
} elseif { [string equal $mode INC] } {
set ifh [open $res r]
while { ![eof $ifh] } {
gets $ifh iline
fputs $iline
}
close $ifh
}
## comment, ignore
continue
}
## Pre-formatted
if {[regexp {^--- (.*)} $_curLine dum res] != 0 } {
if {$stateInPre} {set stateInPre 2}
procPre res stateInPre
continue
}
## ws3 code
if {[regexp {^---ws3 (.*)} $_curLine dum res] != 0 } {
if { [string equal $_state ws3] } {
set _state ""
if { [string length $res] } {
fputs $res
}
fputs </pre>
} else {
set _state ws3
fputs <pre>
if { [string length $res] } {
fputs $res
}
}
continue
}
## Itemize
if {[regexp {^( *)==\* (.*)} $_curLine dum spaces res] != 0 } {
set level [expr [string length $spaces] / 4 + 1]
if { $level == $_level } {
# continue on current level
procItemize $res
} elseif {$level < $_level } {
# level decreased
for {set i $_level } {$i > $level} {incr i -1} {
endList $i
}
procItemize $res
} else {
# new level
procItemizeStart $res
}
continue
}
## Enum
if {[regexp {^( *)==1 (.*)} $_curLine dum spaces res] != 0 } {
set level [expr [string length $spaces] / 4 + 1]
if { $level == $_level } {
procEnum $res
} elseif {$level < $_level } {
for {set i $_level } {$i > $level} {incr i -1} {
endList $i
}
procEnum $res
} else {
procEnumStart $res
}
continue
}
## Description
if {[regexp {^( *)==D (.*)} $_curLine dum spaces res] != 0 } {
#==D foo
# bar
#1234==D foo
set level [expr [string length $spaces] / 4 + 1]
# puts "DBG processing desc, level: $level ($_level) ($_state)"
if { $level == $_level } {
# continue on current level
procDesc $res 1
} elseif {$level < $_level } {
for {set i $_level } {$i > $level} {incr i -1} {
endList $i
}
procDesc $res 1
} else {
# new level
procDescStart $res
}
continue
}
## Table
if {[regexp {^==T (.*)} $_curLine dum res] != 0 } {
procTable res stateInTable
continue
}
if { [isH1 $_curLine res aname] } {
set _cur_h1 $res
if { $_split_level == 1 } {
closeOutputFile
openNextOutputFile
}
procH1 $res
continue
} elseif {[isH2 $_curLine res aname] } {
## H2
procH2 $res
continue
} elseif {[isH3 $_curLine res aname] } {
## H3
procH3 $res
continue
}
## Figure
# if {[regexp {^==Figure==([^=]*)==([^=]*)==(.*)} $_curLine dum id url alt]
# != 0 } {}
if {[regexp {^==Figure==([^=]*)==([^=]*)={0,2}(.*)} $_curLine dum id url alt]
!= 0 } {
#puts stderr "DBG syp.tcl -- found Figure."
#puts stderr "DBG syp.tcl -- next line: $_nextLine."
## -- ok, this is a special case. Try to read the caption. --
set caption {}
if {[regexp {^ (.*)} $_nextLine dum res] != 0 } {
set caption $res
#puts stderr "DBG syp.tcl -- caption: $caption."
while {[eof $fh] == 0} {
_getNextInputLine $fh
if {[regexp {^ (.*)} $_nextLine dum res] != 0 } {
append caption "\n$res"
} else {
break
}
}
}
procFigure $id $url $alt $caption
continue
}
# continuation
if {[regexp {^( +)(.*)} $_curLine dum spaces res] != 0 } {
if { [string equal $_state ws3] } {
## websh3 code
procWS3Code [web::dehtmlify $res]
continue
}
set level [expr [string length $spaces] / 4]
# puts "DBG is continuation, level: $level, state: $_state, actual level: $_level, in: $res"
if { $level >= 1 } {
if {[string equal $_state ul]} {
if {$level < $_level } {
for { set i $_level } {$i <= $level} {incr i -1} {
procItemizeEnd
}
procItemize $res
} else {
fputs $res
# procItemize $res
}
} elseif {[string equal $_state ol]} {
if {$level < $_level } {
for { set i $_level } {$i <= $level} {incr i -1} {
procEnumEnd
}
procEnum $res
} else {
fputs $res
# procEnum $res
}
} elseif {$stateInTable} {
procTable res stateInTable
} elseif {[string equal $_state dl]} {
if {$level < $_level } {
# level decreased
for { set i $_level } {$i <= $level} {incr i -1} {
procDescEnd
procDesc $res
}
} else {
fputs $res
# procDesc $res
}
} else {
# puts "DBG unmatched continuation 1: $res"
fputs $_curLine
}
} else {
# puts "DBG unmatched continuation 2: $res"
fputs $_curLine
}
continue
}
## so it was a termination ?
set dum ""
if {[string equal $_state ul]} {
for { set i $_level } {$i > 0} {incr i -1} {
endList $i
}
} elseif {[string equal $_state ol]} {
for { set i $_level } {$i > 0} {incr i -1} {
endList $i
}
} elseif {$stateInTable} {
set stateInTable 2
procTable dum stateInTable
} elseif {[string equal $_state dl]} {
# puts "DBG processing term, ($_level) ($_state)"
for { set i $_level } {$i > 0} {incr i -1} {
endList $i
}
}
## just text
fputs $_curLine
}
close $fh
}
proc splitFileName {{cnt -1}} {
global _outBaseName
set base [file rootname ${_outBaseName}]
set ext [file extension ${_outBaseName}]
if { $cnt > -1 } {
set fn "${base}${cnt}${ext}"
} else {
set fn $_outBaseName
}
}
proc openNextOutputFile {} {
global _ofh
global _tfh
global _split_cnt
global _split_level
global _split_first
global _split_last
global _template
global _cur_h1
if { $_split_level } {
incr _split_cnt
set fn [splitFileName $_split_cnt]
} else {
set fn [splitFileName]
}
# puts "DBG opening $fn"
set _ofh [open $fn w]
# -------------------------------------------------------------------------
# use template, if any
# -------------------------------------------------------------------------
if { [string length $_template] } {
set _tfh [open $_template r]
while { [eof $_tfh] == 0 } {
gets $_tfh template_line
if {[regexp {^%%%H1(.*)} $template_line]} {
fputs $_cur_h1
continue
}
if {[regexp {^%%%FIRST(.*)} $template_line]} {
fputs "<a href=\"[splitFileName $_split_first]\">[web::htmlify "<<"]</a>"
continue
}
if {[regexp {^%%%LAST(.*)} $template_line]} {
fputs "<a href=\"[splitFileName $_split_last]\">[web::htmlify ">>"]</a>"
continue
}
if {[regexp {^%%%NEXT(.*)} $template_line]} {
set cnt $_split_cnt
incr cnt
if { $cnt <= $_split_last } {
fputs "<a href=\"[splitFileName $cnt]\">[web::htmlify ">"]</a>"
} else {
fputs [web::htmlify ">"]
}
continue
}
if {[regexp {^%%%PREV(.*)} $template_line]} {
set cnt $_split_cnt
incr cnt -1
if { $cnt >= $_split_first } {
fputs "<a href=\"[splitFileName $cnt]\">[web::htmlify "<"]</a>"
} else {
fputs [web::htmlify "<"]
}
continue
}
if {[regexp {^%%%TMPL(.*)} $template_line]} {
break
} else {
fputs $template_line
}
}
}
}
proc closeOutputFile {} {
global _ofh
global _tfh
global _template
global _split_first
global _split_last
global _split_cnt
# puts "DBG closing"
# -------------------------------------------------------------------------
# finish template file, if any
# -------------------------------------------------------------------------
if { [string length $_template] } {
while { [eof $_tfh] == 0} {
gets $_tfh template_line
if {[regexp {^%%%FIRST(.*)} $template_line]} {
fputs "<a href=\"[splitFileName $_split_first]\">[web::htmlify "<<"]</a>"
continue
}
if {[regexp {^%%%LAST(.*)} $template_line]} {
fputs "<a href=\"[splitFileName $_split_last]\">[web::htmlify ">>"]</a>"
continue
}
if {[regexp {^%%%NEXT(.*)} $template_line]} {
set cnt $_split_cnt
incr cnt
if { $cnt <= $_split_last } {
fputs "<a href=\"[splitFileName $cnt]\">[web::htmlify ">"]</a>"
} else {
fputs [web::htmlify ">"]
}
continue
}
if {[regexp {^%%%PREV(.*)} $template_line]} {
set cnt $_split_cnt
incr cnt -1
if { $cnt >= $_split_first } {
fputs "<a href=\"[splitFileName $cnt]\">[web::htmlify "<"]</a>"
} else {
fputs [web::htmlify "<"]
}
continue
}
fputs $template_line
}
close $_tfh
}
close $_ofh
}
proc init {} {
global _state
global _level
global _split_cnt
global _split_level
global _split_first
global _split_last
global _level_stack
global _cur_h1
set _state {}
set _level 0
set _split_cnt 0
set _split_level 0
set _split_first 1
set _split_last 0
set _cur_h1 {}
}
proc usage {arglist switches} {
puts stderr "usage: syp input outputBase \[options\]"
puts stderr " e.g. syp in.syp out.html"
foreach {name arg desc} $arglist {
puts stderr " -$name $arg $desc"
}
foreach {name desc} $switches {
puts stderr " -$name $desc"
}
}
proc main {argc argv} {
global _filename
global _template
global _ofh
global _outBaseName
global _split_level
set arglst {
split <level> "one output file per h1,h2,... section - <level> is int"
tr <module> "use <module> for output generation"
template <file> "use <file> as template for output"
}
set switches {}
# -------------------------------------------------------------------------
# command line
# -------------------------------------------------------------------------
if {$argc > 1 } {
set _filename [lindex $argv 0]
set _outBaseName [lindex $argv 1]
} else {
usage $arglst $switches
exit 1
}
if {$argc > 2 } {
foreach {name vale desc} $arglst {
# -----------------------------------------------------------------
# (-tr) load module, if any
# -----------------------------------------------------------------
set idx [lsearch $argv "-tr"]
if { $idx != -1} {
source [lindex $argv [expr $idx + 1]]
}
# -----------------------------------------------------------------
# (-split)
# -----------------------------------------------------------------
set idx [lsearch $argv "-split"]
if { $idx != -1} {
set _split_level [lindex $argv [expr $idx + 1]]
if { ![string is integer $_split_level] } {
puts "error: argument for -split must be integer, not $_split_level"
exit 1
}
puts "DBG split: $_split_level"
}
# -------------------------------------------------------------------
# (-template) load template, if any
# -------------------------------------------------------------------
set idx [lsearch $argv "-template"]
if { $idx != -1} {
set _template [lindex $argv [expr $idx + 1]]
if { ![file exists $_template] } {
puts "error: file $_template does not exist"
exit 1
}
}
}
}
# -------------------------------------------------------------------------
# file exists ?
# -------------------------------------------------------------------------
if {![file exists $_filename] } {
puts stderr "syp.tcl --- cannot read $_filename"
exit 1
}
# -------------------------------------------------------------------------
# first scan: build list of figures and references
# -------------------------------------------------------------------------
_firstScan $_filename
openNextOutputFile
_mainScan $_filename
closeOutputFile
}
init
main $argc $argv
1.1 tcl-site/websh/syp2txt.tcl
Index: syp2txt.tcl
===================================================================
# -----------------------------------------------------------------------------
# syp2txt - plug-in for syp: convert to text
# nca-115-2
# $Id: syp2txt.tcl,v 1.1 2002/05/08 10:31:09 davidw Exp $
# -----------------------------------------------------------------------------
set _syp_mode TXT
# ----------------------------------------------------------------------------
# tags
# ----------------------------------------------------------------------------
proc boldify {tmp} {return "$tmp"}
proc italicify {tmp} {return "$tmp"}
proc preify {tmp} {return "$tmp"}
proc newLine {} {return "\n"}
proc hrefify {tmp {t2 ""}} {
if { "$t2" == "" } { set t2 $tmp }
return "$tmp"
}
# ----------------------------------------------------------------------------
# default processors
# ----------------------------------------------------------------------------
proc procH {type str {aName ""}} {
if {[string equal $type "h1"]} {
set symb "="
} elseif {[string equal $type "h2"]} {
set symb "-"
} elseif {[string equal $type "h3"]} {
set symb "."
}
puts "$str"
for {set i 0} {$i < [string length $str]} {incr i} {
puts -nonewline "$symb"
}
puts ""
puts ""
}
proc procH1 {str {aName ""}} { procH h1 $str $aName }
proc procH2 {str {aName ""}} { procH h2 $str $aName }
proc procH3 {str {aName ""}} { procH h3 $str $aName }
proc procList {type item vStr vState {isItem 0}} {
upvar $vStr str
upvar $vState state
if {$state == 0} {
set state 1
set isItem 1
} elseif {$state == 2} {
set state 0
return
}
if {$isItem } {
puts "$item $str"
} else {
puts "$str"
}
}
proc procItemize {vStr vState {isItem 0}} {
upvar $vStr str
upvar $vState state
return [procList "" * str state $isItem]
}
proc procEnum {vStr vState {isItem 0}} {
upvar $vStr str
upvar $vState state
global _enumcnt
if {$state == 0} {set _enumcnt 0}
return [procList "" "$_enumcnt." str state $isItem]
}
proc procDesc {vStr vState {isDesc 0}} {
upvar $vStr str
upvar $vState state
if {$state == 0} {
set state 1
set isDesc 1
} elseif {$state == 2} {
set state 0
return
}
if {$isDesc } {
puts "$str:"
} else {
puts " $str"
}
}
proc procPre {vStr vState} {
upvar $vStr str
upvar $vState state
if {$state == 0} {
puts "$str"
set state 1
return
} elseif {$state == 2} {
puts "$str"
set state 0
return
}
}
proc procTable {vStr vState} {
upvar $vStr str
upvar $vState state
global _sypTableRow
set cols [split $str {|}]
if {$state == 0} {
foreach col $cols {
puts "[boldify [string trim $col]]"
}
set state 1
set _sypTableRow 1
return
} elseif {$state == 2} {
set state 0
return
}
if {$_sypTableRow} {
set _sypTableRow 0
} else {
set _sypTableRow 1
}
foreach col $cols {
puts "[string trim $col]"
}
}
proc procPara {} {
puts [newLine]
}
proc procFigRef {id} {
return "Figure [findFigRef $id]"
}
proc procFigure {id url shortdesc caption} {
set tmp [procFigRef $id]
puts "\[Figure $shortdesc ($url)\]"
puts "$tmp - $caption"
}
proc procIndex {{title ""} {anchor ""}} {
global _sypidx
if {[string length $title] < 1} { set title "index" }
if {[string length $anchor] < 1} { set anchor $title }
if { [info exists _sypidx] } {
procPara
procH1 $title $anchor
set i 0
foreach ent $_sypidx {
set type [lindex $ent 0]
set link [lindex $ent 1]
set text [lindex $ent 2]
if {[string equal $type "h1"] || [string equal $type "h2"] } {
if { [string compare $type "h2"] == 0 } {
puts -nonewline " -"
} else {
puts -nonewline "$i "
incr i
}
puts "$text"
}
}
}
}
proc conformify {in} { return $in }
1.1 tcl-site/websh/tutorial.syp
Index: tutorial.syp
===================================================================
== webshell tutorial ==
This tutorial demonstrates the first steps with
webshell. We assume that you are familiar with Tcl syntax.
-- webshell concepts --
In the following, we will use the webshell concepts
for command dispatching, output management, formvar management, and
logging. The respective webshell commands we will use are
==* web::command
==* web::cmdurl
==* web::put
==* web::putx
==* web::formvar
==* web::param
==* web::log
==* web::logfilter
==* web::logdest
-- task --
Create a script that shows an HTML form and handles its submission
Challenge: the form must at least supply three fields: a name, an
address and an e-mail address (the address field should be a
<pre><textarea></pre> field) the reply after the submission must
reflect the input the script must provide two commands: the default,
and the submit command.
-- solution --
<pre>
#!/websh3
# default command
web::command default {
# note: it's usually more efficient to take web::eval instead of web::puts
# to output composed strings and header and footer procs usually generate
# their own output. -> see step 2 for a better implementation
web::puts "[header Form]
<form method=post action=\"[web::cmdurl submit]\">
<dl>
<dt><b>Name:</b>
<dd><input type=text name=name value=\"\" size=30><p>
<dt><b>Address:</b>
<dd><textarea name=addr rows=4 cols=30 wrap=auto></textarea><p>
<dt><b>E-Mail:</b>
<dd><input type=text name=email value=\"\" size=30><p>
</dl>
<input type=reset name=cancel value=\"Reset\">
<input type=submit name=ok value=\"Send\">
</form>
[footer]"
}
# submit command
web::command submit {
# take care of linebreaks in address
regsub -all "\r\n" [web::htmlify [web::formvar addr]] "<br>" addr
# note: it's usually more efficient to take web::eval instead of web::puts
# to output composed strings and header and footer procs usually generate
# their own output. -> see step 2 for a better implementation
web::puts "[header Confirmation]
<h3>Thank you ...</h3>
<dl>
<dt><b>Name:</b>
<dd>[web::htmlify [web::formvar name]]<p>
<dt><b>Address:</b>
<dd>$addr<p>
<dt><b>E-Mail:</b>
<dd>[web::htmlify [web::formvar email]]<p>
</dl>
[footer]"
}
proc header {{title ""}} {
set completeTitle "Websh Tutorial - Step 1 - $title"
return "<html>
<head>
<title>$completeTitle</title>
</head>
<body bgcolor=\"\#ffffff\" text=\"\#000000\">
<h2>$completeTitle</h2>
"
}
proc footer {} {
return "</body>
</html>
"
}
</pre>
1.1 tcl-site/websh/tutorial.ws3
Index: tutorial.ws3
===================================================================
## www.websh.com/tutorial.html
## nca-115-2
## $Id: tutorial.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 2
web::putx {
<!-- body -->
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 3 "tutorial"}
<tr valign="top">
{navbar_docu 3}
<td width="610">
<!-- main content starts here -->
<h1>Tutorial</h1>
This tutorial demonstrates the first steps with
webshell. We assume that you are familiar with Tcl syntax.
The task is to build a HTML form to gather information
from users.
<h2>Challenge</h2>
<ul>
<li>the form must at least supply three fields: a name, an address and an
e-mail address (the address field should be a <b><tt><textarea></tt></b>
field)
<li>the confirmation after submission must repeat the input
<li>the webshell application must check for valid e-mail addressed
</ul>
<h2>Solution</h2>
Here is an <a href="example_form.ws3">example</a>.
<!-- main content ends here -->
</td>
</tr>
</table>
}
finishPage 2
1.1 tcl-site/websh/unsubscribe.ws3
Index: unsubscribe.ws3
===================================================================
## www.websh.com/unsubscribe.html
## nca-115-2
## $Id: unsubscribe.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 0
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 3 "webshell newsletter"}
<tr valign="top">
{navbar_null}
<td width="610">
You can
unsubscribe from the webshell newsletter by simply
adding your e-mail address below.<br>
<FORM action="/bin/mail/websh_news?cmd=unsubscribe" method="POST">
<INPUT TYPE="TEXT" SIZE="40" MAXLENGTH="60" NAME="user">
<INPUT type="submit" value="unsubscribe">
</FORM>
<br>
Alternatively, you may unsubscribe from the newsletter by
sending an e-mail to {emailLink majordomo@netcetera.ch} with
<tt>unsubscribe websh-news</tt> in the body of the message.
<br><br><br>
Thank you for you interest in webshell.
</td>
</tr>
</table>
}
finishPage
1.1 tcl-site/websh/upload.sample
Index: upload.sample
===================================================================
#! ../../bin/websh3
# This example demonstrates you how "file upload": sending
# a file to the server thru a html form.
# allow file upload
# uploadfilesize defines the maximum file size upload
# in this case 100 bytes
web::config uploadfilesize 100
# utility command to handle an HTML page
proc page {title code} {
web::putx {<html><head><title>{web::put $title}</title></head>
<body bgcolor="#ffffff" text="#000000">
<h3>{web::put $title}</h3>
}
uplevel $code
web::put "</body></html>\n"
}
# utility command to handle an html form
proc form {page code} {
web::put "<form enctype=\"multipart/form-data\" method=\"post\" action=\"[web::cmdurl $page]\">"
uplevel $code
web::put "</form>"
}
proc showForm {error} {
# generate a page with Title "File upload example"
page "File upload example" {
# generate a form with action "submit"
form "submit" {
web::putx {{
# if "error" flag is set, show the red error message asking for input
if {$error == 1} {
web::put "<font color=\"\#990000\">If you'd like to upload a file,\n you have to insert the path and file name <br></font>"
}
}
<b>File:</b> <input type="file" size="30" name="upload" value="{web::put [web::formvar upload]}"> <input type="submit" name="ok" value="Send">
}
}
}
}
# validator:
#
# make sure we have a name that is more than 1.
proc checkFormData {} {
# string lenght gets the lenght
# "lindex [...] 1" is getting the first line from the list in the variable
if { [string length [lindex [web::formvar upload] 1]] < 1} {
# return error code
return 1
}
# looks good: no error
return 0
}
proc showConfirmationPage {} {
# gets return value from list upload
set localname [lindex [web::formvar upload] 0]
set remotename [lindex [web::formvar upload] 1]
set NumBytesTruncated [lindex [web::formvar upload] 2]
# open pipe for reading uploaded file
set fh [open $localname r]
set chunk [read $fh 10]
close $fh
page "File upload example" {
web::putx {
<b>We have received your file. Thank you.<br><br>
Technical information:</b>
<br>
<table border="0" width="300">
<tr>
<td width="100">
File-path:</td><td width="200">{web::put [web::htmlify $localname]}</td></tr>
<tr>
<td width="100">
Localpath:</td><td width="200">{web::put [web::htmlify $remotename]}</td></tr>
<tr>
<td width="300" colspan="2">
We have configured websh3 to allow a maximum file size of 100 bytes. Therefore
we have truncated the received file by {web::put $NumBytesTruncated} bytes.
</td></tr>
<tr>
<td width="100">Start of content:</td><td width="200">{web::put [web::htmlify $chunk]}</td></tr></table>
<a href="upload">upload another file</a>
}
}
}
# register the "default" command
#
# See confirmation form example.
web::command default {
showForm 0
}
# register command "submit"
#
# This is the "action" of our form. See confirmation form example.
web::command submit {
if { [set res [checkFormData]] == 0 } {
showConfirmationPage
} else {
showForm $res
}
}
#see dispatch example
web::dispatch
1.1 tcl-site/websh/websh.com.gen
Index: websh.com.gen
===================================================================
# -*- Tcl -*-
# -----------------------------------------------------------------------------
# webshell.com.gen -- reusable parts
# nca-115-2
#
# $Id: websh.com.gen,v 1.1 2002/05/08 10:31:09 davidw Exp $
# -----------------------------------------------------------------------------
proc includeFile {fileName} {
if {[file exists $fileName] } {
set fileId [open $fileName "r"]
while {[eof $fileId] == 0} {
gets $fileId tLine
web::put "$tLine\n"
}
}
}
proc pageLink {url args} {
set showName $url
foreach {arg value} $args {
switch -- $arg \
-show { set showName $value} \
-pre { set url "http://$url" }
}
web::put "<a href=\"$url\">$showName</a>"
}
proc emailLink {email {showName ""}} {
if { [string compare $showName ""] == 0 } {set showName $email }
pageLink mailto:$email -show $showName
}
proc emailFeedbackLink {} {
emailLink support@websh.com feedback
}
proc emailSupportLink {} {
emailLink support@websh.com
}
proc emailInfoLink {} {
emailLink info@websh.com
}
proc headRow {type mainTitle {rightTitle ""}} {
if {$type == 1} {
puts stderr "websh.com.gen -- proc header cannot format type 1"
return
}
web::putx {
<tr height="30">
<td width="10" valign="top"></td>
<td width="150" height="30"></td>
{
if {$type == 2} {
web::putx {
<td width="300" height="30">
{if {[string length $mainTitle] > 0 } {
web::putx {<h1>{web::put $mainTitle}</h1>}
} else {
web::putx { }
}}
</td>
<td width="10" height="30"><br>
</td>
<td width="300" height="30">
{if {[string length $rightTitle] > 0 } {
web::putx {<h1>{web::put $rightTitle}</h1>}
} else {
web::putx { }
}}
</td>
}
}
if {$type == 3} {
web::putx {
<td width="610" height="30">
{if {[string length $mainTitle] > 0 } {
web::putx {<h1>{web::put $mainTitle}</h1>}
} else {
web::putx { }
}}
</td>
}
}
if {$type == 4} {
web::putx {
<td width="455" height="30">
{if {[string length $mainTitle] > 0 } {
web::putx {<h1>{web::put $mainTitle}</h1>}
} else {
web::putx { }
}}
</td>
<td width="10" height="30"><br>
</td>
<td width="145" height="30">
{if {[string length $rightTitle] > 0 } {
web::putx {<h1>{web::put $rightTitle}</h1>}
} else {
web::putx { }
}}
</td>
}
}
}
</tr>
}
}
proc navBarElementSub {ref str flag} {
if { $flag == 1 } {
web::putx {
- <a href="{web::put $ref}">{web::put $str}</a><br>
}
return
}
if { $flag == 0 } {
web::putx {
- {web::put $str}<br>
}
return
}
if { $flag == 2 } {
web::putx {
- <span class=grey>{web::put $str}</span><br>
}
return
}
}
proc navBarElementOne {ref str flag} {
if { $flag == 1 } {
web::putx {<a href="{web::put $ref}"><b>{web::put $str}</b></a><br>
}
return
}
if { $flag == 0 } {
web::putx {<b>{web::put $str}</b><br>
}
return
}
if { $flag == 2 } {
web::putx {<b class=grey>{web::put $str}</b><br>
}
return
}
}
proc navBarElement {ref str flag args} {
web::putx {
<tr valign="top">
<td width="10"><img height="11" width="10" src="images/pfeil.gif"></td>
<td class=nav>
{
navBarElementOne $ref $str $flag
foreach {arg value isLink} $args {
navBarElementSub $arg $value $isLink
}
}
<br></td></tr>
}
}
proc navBarStart {} {
web::putx {
<td width="10"><img height="1" border="0" width="10" src="images/stuntFFFFFF001010.gif"></td>
<td width="150">
<table border="0" cellpadding="0" cellspacing="0" width="141">
}
}
proc navBarEnd {} {
web::putx {
</table>
</td>
}
}
proc redPointElement {text} {
web::putx {
<tr valign="top">
<td width="10"><img height="10" width="10" src="images/punkt_rot.gif"></td>
<td>{web::putx $text}
</td>
</tr>
}
}
proc newsBarElement {title {desc ""}} {
web::putx {
<tr valign="top">
<td width="10"><img height="10" width="10" src="images/punkt_rot.gif"></td>
<td class=news><b>{web::putx $title}</b><br>
{web::putx $desc}
</td>
</tr>
}
}
proc newsBarElementGrey {title {desc ""}} {
web::putx {
<tr valign="top">
<td width="10"><img height="10" width="10" src="images/punkt_grau.gif"></td>
<td class=grey><b>{web::putx $title}</b><br>
{web::putx $desc}
</td>
</tr>
}
}
proc pageLink {url args} {
set showName $url
foreach {arg value} $args {
switch -- $arg \
-show { set showName $value} \
-pre { set url "http://$url" }
}
web::put "<a href=\"$url\">$showName</a>"
}
proc uppfeil {link args} {
set aName ""
set text ""
foreach {arg value} $args {
switch -- $arg \
-aName { set aName $value} \
-text { set text $value }
}
web::putx {
<tr valign="top">
{navBarStart}
<tr valign="top">
<td width="10"><a href="{web::putx $link}"><img height="10" border="0" width="10" src="images/uppfeil.gif"></a></td>
<td></td>
</tr>
{navBarEnd}
<td width="455">
{
if {[string compare $aName ""] == 0 } {
web::putx {<h2 class=nomargin>{web::putx $text}</h2>}
} else {
web::putx {<h2 class="nomargin"><a name="{web::put $aName}">{web::putx $text}</a></h2>}
}
}
</td>
</tr>
}
}
## ============================================================================
## navigation bars
## ============================================================================
proc navbar_prod {{where 0}} {
web::putx {
{navBarStart}
{navBarElement "product.ws3" "product description" [expr $where != 0] \
"#history" "history" 1 \
"#tcl" "based on Tcl" 1 \
"#design" "design" 1}
{navBarElement "TBD" "webshell in action" 2}
{navBarElement "TBD" "success stories" 2}
{navBarElement "TBD" "comparison chart" 2}
{navBarEnd}
}
}
proc navbar_docu {{where 0}} {
web::putx {
{navBarStart}
{navBarElement "docu.ws3" "documentation" [expr $where != 0]}
{navBarElement "whitepaper.ws3" "white paper" [expr $where != 1] \
"whitepaper.ws3#toc" "index" 1}
{navBarElement "quickref.ws3" "quick reference" [expr $where != 2] \
"quickref.ws3#toc" "index" 1}
{navBarElement "tutorial.ws3" "tutorial" 2}
{navBarElement "examples.ws3" "examples" [expr $where != 4]}
{navBarElement "reference.ws3" "reference" 2}
{navBarEnd}
}
}
proc navbar_supp {{where 0}} {
web::putx {
<td width="10"><br></td>
<td width="150">
<table border="0" cellpadding="0" cellspacing="0" width="141">
{navBarElement "support.ws3" "support" [expr $where != 0]}
{navBarElement "faq.ws3" "faq" [expr $where != 1] \
"faq.ws3#generic" "generic questions" 1 \
"faq.ws3#technical" "technical questions" 1 \
"faq.ws3#toc" "index" 1}
{navBarElement "subscribe.ws3" "mailing list" 1}
{navBarElement "bin/bugsubmit" "bug submission" [expr $where != 3]}
{navBarElement {/bin/bugdb" onclick="javascript:window.open('','bugdb','width=500,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="bugdb} "bug tracking" 2}
</table>
</td>
}
}
proc navbar_ress {{where 0}} {
web::putx {
{navBarStart}
{navBarEnd}
}
}
proc navbar_down {{where 0}} {
web::putx {
{navBarStart}
{navBarEnd}
}
}
proc navbar_null {} {
web::putx {
<td width="10"><img height="1" border="0" width="10" src="images/stuntFFFFFF001010.gif"></td>
<td width="150"> </td>
}
}
## ============================================================================
## news bars
## ============================================================================
proc newsbar_supp {} {
web::putx {
<td width="10"><br></td>
<td width="145">
<table border="0" cellpadding="0" cellspacing="0" width="145">
{newsBarElement "free e-mail support" \
"For webshell support, simply send an e-mail to {emailSupportLink}"
}
{newsBarElement "maintenance contracts" \
{Netcetera offers specially tailored maintenance contracts.
For inquiries, contact us at {emailInfoLink}.}
}
{newsBarElement "Feedback" \
{{emailLink support@websh.com "Please let us know"}
what you think about webshell. Your feedback
will help us make a great product even better.}
}
</table>
</td>
}
}
proc newsbar_ress {} {
web::putx {
<td width="10"></td>
<td width="145">
<table border="0" cellpadding="0" cellspacing="0" width="145">
{newsBarElement "Netcetera @ Orbit" \
{Meet our experts at the
{pageLink www.orbit-comdex.ch -show "Orbit/Comdex" -pre}.
}
}
</table>
</td>
}
}
proc jslink {linkname generic onover onout width gif alt} {
return "<a href=\"$linkname\" \
onmouseover=\"wechsel('$generic','$onover')\" \
onmouseout=\"wechsel('$generic','$onout')\"><img height=\"20\" \
width=\"$width\" \
src=\"buttons/$gif\" \
name=\"$generic\" border=\"0\" alt=\"$alt\"></a>"
}
proc startHtmlPage {} {
web::putx {
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<title>webshell - Welcome</title>
<script language="JavaScript" src="buttons.js"></script>
<link href="websh.css" rel="styleSheet" type="text/css">
<meta name="description" content="webshell - the rapid development environment to build powerful web applications.">
<META NAME="keywords" CONTENT="websh, webshell, e-commerce, web application, apache, perl, php, asp, cold fusion">
</head>
}
}
proc startHtmlBody {} {
web::putx {
<body marginwidth="0" marginheight="0" topmargin="0" leftmargin="0"
bgcolor="#ffffff" link="#006699" alink="red" vlink="#006699">
}
}
proc putHeader {{mainSectionNr 0} {quickNaviNr 1}} {
web::putx {
<map name="grafik_navi">
<area href="mailto:info@websh.com" coords="94,2,154,26" shape="rect">
<area href="" coords="4,2,64,26" shape="rect">
<area href="contact.ws3" coords="184,2,244,26" shape="rect">
</map>
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="76">
<tr valign="top">
}
if {$quickNaviNr == 0} {
web::putx {
<td width="500" bgcolor="#006699"><img height="50" width="300" src="images/grafik_navi.gif" alt="quick navigation" border="0" usemap="#grafik_navi"><img height="50" width="200" src="images/grafik_index.gif" alt="drawing"></td>
}
} else {
web::putx {
<!-- quick navigation --><!-- map --><!-- technical drawing -->
<td width="500" bgcolor="#006699"><img height="50" width="300" src="images/grafik_navi_home.gif" alt="quick navigation" border="0" usemap="#grafik_navi"><img height="50" width="200" src="images/grafik_index.gif" alt="drawing"></td>
}
}
web::putx {
<td><img height="50" width="270" src="images/logo.gif" alt="websh"></td>
<td width="5000" bgcolor="#000000"> </td>
</tr>
<tr>
<td width="500">
<table border="0" cellpadding="0" cellspacing="0" width="500" height="40">
}
if {$mainSectionNr == 0} {
web::putx {
<tr>
<td>{web::put [jslink product.ws3 prod b_prod_b b_prod_a 120 b_prod_a.gif "product description"]}</td>
<td>{web::put [jslink docu.ws3 docu b_docu_b b_docu_a 100 b_docu_a.gif "documentation"]}</td>
<td>{web::put [jslink support.ws3 supp b_supp_b b_supp_a 70 b_supp_a.gif "support"]}</td>
<td>{web::put [jslink resources.ws3 ress b_ress_b b_ress_a 110 b_ress_a.gif "resources and links"]}</td>
<td>{web::put [jslink download.ws3 down b_down_b b_down_a 100 b_down_a.gif "download"]}</td>
</tr>
<tr>
<td colspan="5"><img height="20" width="500" src="titles/t_neutral.gif" alt="lines"></td>
</tr>
}
}
if {$mainSectionNr == 1} {
web::putx {
<tr bgcolor="#006699">
<td width="120"><br></td>
<td>{web::put [jslink docu.ws3 docu b_docu_b b_docu_a 100 b_docu_a.gif "documentation"]}</td>
<td>{web::put [jslink support.ws3 supp b_supp_b b_supp_a 70 b_supp_a.gif "support"]}</td>
<td>{web::put [jslink resources.ws3 ress b_ress_b b_ress_a 110 b_ress_a.gif "resources and links"]}</td>
<td>{web::put [jslink download.ws3 down b_down_b b_down_a 100 b_down_a.gif "download"]}</td>
</tr>
<tr height="20">
<td width="120" height="20"><img height="20" width="120" src="buttons/b_prod_c.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="titles/strich2.gif"></td>
<td width="70" height="20"><img height="20" width="70" src="titles/strich2.gif"></td>
<td width="110" height="20"><img height="20" width="110" src="titles/strich2.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="titles/strich2.gif"></td>
</tr>
}
}
if {$mainSectionNr == 2} {
web::putx {
<tr bgcolor="#006699">
<td>{web::put [jslink product.ws3 prod b_prod_b b_prod_a 120 b_prod_a.gif "product description"]}</td>
<td width="100"><br></td>
<td>{web::put [jslink support.ws3 supp b_supp_b b_supp_a 70 b_supp_a.gif "support"]}</td>
<td>{web::put [jslink resources.ws3 ress b_ress_b b_ress_a 110 b_ress_a.gif "resources and links"]}</td>
<td>{web::put [jslink download.ws3 down b_down_b b_down_a 100 b_down_a.gif "download"]}</td>
</tr>
<tr height="20">
<td width="120" height="20"><img height="20" width="120" src="titles/strich2.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="buttons/b_docu_c.gif"></td>
<td width="70" height="20"><img height="20" width="70" src="titles/strich2.gif"></td>
<td width="110" height="20"><img height="20" width="110" src="titles/strich2.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="titles/strich2.gif"></td>
</tr>
}
}
if {$mainSectionNr == 3} {
web::putx {
<tr bgcolor="#006699">
<td>{web::put [jslink product.ws3 prod b_prod_b b_prod_a 120 b_prod_a.gif "product description"]}</td>
<td>{web::put [jslink docu.ws3 docu b_docu_b b_docu_a 100 b_docu_a.gif "documentation"]}</td>
<td width="70"><br></td>
<td>{web::put [jslink resources.ws3 ress b_ress_b b_ress_a 110 b_ress_a.gif "resources and links"]}</td>
<td>{web::put [jslink download.ws3 down b_down_b b_down_a 100 b_down_a.gif "download"]}</td>
</tr>
<tr height="20">
<td width="120" height="20"><img height="20" width="120" src="titles/strich2.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="titles/strich2.gif"></td>
<td width="70" height="20"><img height="20" width="70" src="buttons/b_supp_c.gif"></td>
<td width="110" height="20"><img height="20" width="110" src="titles/strich2.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="titles/strich2.gif"></td>
</tr>
}
}
if {$mainSectionNr == 4} {
web::putx {
<tr bgcolor="#006699">
<td>{web::put [jslink product.ws3 prod b_prod_b b_prod_a 120 b_prod_a.gif "product description"]}</td>
<td>{web::put [jslink docu.ws3 docu b_docu_b b_docu_a 100 b_docu_a.gif "documentation"]}</td>
<td>{web::put [jslink support.ws3 supp b_supp_b b_supp_a 70 b_supp_a.gif "support"]}</td>
<td width="110"><br></td>
<td>{web::put [jslink download.ws3 down b_down_b b_down_a 100 b_down_a.gif "download"]}</td>
</tr>
<tr height="20">
<td width="120" height="20"><img height="20" width="120" src="titles/strich2.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="titles/strich2.gif"></td>
<td width="70" height="20"><img height="20" width="70" src="titles/strich2.gif"></td>
<td width="110" height="20"><img height="20" width="110" src="buttons/b_ress_c.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="titles/strich2.gif"></td>
</tr>
}
}
if {$mainSectionNr == 5} {
web::putx {
<tr bgcolor="#006699">
<td>{web::put [jslink product.ws3 prod b_prod_b b_prod_a 120 b_prod_a.gif "product description"]}</td>
<td>{web::put [jslink docu.ws3 docu b_docu_b b_docu_a 100 b_docu_a.gif "documentation"]}</td>
<td>{web::put [jslink support.ws3 supp b_supp_b b_supp_a 70 b_supp_a.gif "support"]}</td>
<td>{web::put [jslink resources.ws3 ress b_ress_b b_ress_a 110 b_ress_a.gif "resources and links"]}</td>
<td width="100"><br></td>
</tr>
<tr height="20">
<td width="120" height="20"><img height="20" width="120" src="titles/strich2.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="titles/strich2.gif"></td>
<td width="70" height="20"><img height="20" width="70" src="titles/strich2.gif"></td>
<td width="110" height="20"><img height="20" width="110" src="titles/strich2.gif"></td>
<td width="100" height="20"><img height="20" width="100" src="buttons/b_down_c.gif"></td>
</tr>
}
}
web::putx {
</table>
</td>
<td><img height="40" width="270" src="images/logo_strich.gif"></td>
</tr>
</table>
}
}
proc finishPage {{where 0}} {
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770" height="45">
<tr valign="top">
<td colspan="2">
<hr noshade size="1">
</td>
</tr>
<tr valign="top">
<td width="10"></td>
<td width="760">
{
if {$where != 1 } {
web::put {<a href="product.ws3">product description</a> |}
} else {
web::put {<span class="blue">product description</span> |}
}
if {$where != 2 } {
web::put { <a href="docu.ws3">documentation</a> |}
} else {
web::put { <span class="blue">documentation</span> |}
}
if {$where != 3 } {
web::put { <a href="support.ws3">support</a> |}
} else {
web::put { <span class="blue">support</span> |}
}
if {$where != 4 } {
web::put { <a href="resources.ws3">resources</a> |}
} else {
web::put { <span class="blue">resources</span> |}
}
if {$where != 5 } {
web::put { <a href="download.ws3">download area</a> |}
} else {
web::put { <span class="blue">download area</span> |}
}
web::put { <a href="copyright.ws3">copyright statement</a> |}
web::put { <a href="privacy.ws3">privacy policy</a>}
}
<br>
<span class="klein"><b>© webshell - by {web::put {<a href="http://netcetera.ch">Netcetera AG</a>}}</b></span></td>
</tr>
</table>
</body>
</html>
}
}
### Process the actual web page
web::include [web::config script]
1.1 tcl-site/websh/websh.css
Index: websh.css
===================================================================
/* www.websh.com/style.css - cascading styles sheet */
/* nca-115-2 */
/* $Id: websh.css,v 1.1 2002/05/08 10:31:09 davidw Exp $ */
body, p, td, th {color:#000000;font-size:10pt;font-family:Verdana,Helvetica,Arial,sans-serif}
pre, tt {font-family:Courier,monospace}
.nav {color:#006699;}
.parahead {color:#006699}
.news {color:#CC0000}
.blue {color:#006699}
.grey {color:#666666}
.nomargin {margin-top:0.0em;margin-bottom:0.0em;}
h1 {color:#006699;font-size:14pt;margin-top:12pt;margin-bottom:10pt;}
h2 {color:#006699;font-size:12pt;margin-top:12pt;margin-bottom:10pt;}
h3 {color:#006699;font-size:10pt}
1.1 tcl-site/websh/whitepaper.syp
Index: whitepaper.syp
===================================================================
== Introduction ==
This white paper describes the key features of webshell, details it's
architecture, and motivates design decisions. The white paper gives
an overview of webshell and does not replace a technical reference.
webshell is a rapid development environment for building powerful and
reliable web applications. It is a standard Tcl extension and is
released as Open Source Software. webshell is versatile and handles
everything from HTML generation to data-base driven one-to-one page
customization. At Netcetera, we have been using it for years for
virtually all our customer projects, which are typically E-commerce
shops or electronic banking applications. webshell is extensible and
portable, and its comprehensive set of commands is easily learned.
webshell can be used in a standard CGI environment or as Apache 2
module. webshell provides a set of commands for
==* web transaction state management
==* session management (server-side sessions; various storage
managers)
==* HTML form handling
==* encryption
==* logging
%%%TOC
== Architecture ==
webshell is a standard Tcl extension, written in C and in Tcl.
It is strictly modularized and thread safe. This section
gives an overview of the webshell architecture.
-- based on Tcl --
webshell is based on the Tool Command Language (Tcl). Tcl is a fast,
comprehensive scripting language as well as a library.
The decision to build webshell on top of Tcl has several
advantages which can be summarized with
"flexibility": configurability, extensability, and portability.
This is illustrated in [==ws3ov==].
==Figure==ws3ov==images/ws3ov.gif
webshell Architecture
Most Web-based applications need to separate items with a high change
rate from other, static parts. Often, the rapidly changing components
are those related to any aspect of output rendering (e.g., HTML
generation) and input processing. Application logic, on the other
hand, remains rather constant. Therefore, Web-based applications need
to support easy modification of the frequently changing parts. For
example, one wishes to modify HTML output without the need to
recompile the entire application. This means that a high level of
configuration flexibility is needed.
Using Tcl as an embedded system, such configurable parts can be
designed as Tcl code snipplets, configuration files and so on. The
application can call and interpret Tcl code whenever necessary. The
Tcl code itself can call back the C-based application and use the
library routines. This offers a high degree of scalablity.
Using a scripting language for web application development thus has
many advantages over traditional approaches. The potential drawback
of an interpreted language is slower execution as compared with a
compiled program. Experience has shown, however, that the advantage
of flexibility is much more important than these potential differences
in execution speed.
-- Tcl --
The Tool Command Language (Tcl, pronounced "tickle"), was created by
John Ousterhout. Tcl development started 1987 at the University
of California at Berkeley. Today, Ousterhout is CEO of "Scriptics
Corporation", which continues to develop Tcl, and markets value added
products for Tcl. Worldwide, about half a million programmers rely on
Tcl.
The Tcl platform was designed with the philosophy in mind
that one should actually
use two or more languages when designing large software systems. One for
manipulating complex internal data structures or where performance is key,
and another, such as Tcl, for writing smallish scripts that tie together
the other pieces, providing hooks for the user to extend.
For the Tcl-script writer, ease of learning, ease of programming and
ease of glueing are more important than performance or facilities for
complex data structures and algorithms. Tcl was designed to make it
easy to drop into a lower language when you come across tasks that
make more sense at a lower level. In this way, the core functionality
can remain small and one needs only to bring along pieces that one
particularly wants or needs.
Tcl is actually two things: a language and a library. First, Tcl is a
powerful textual language, intended primarily for issuing commands to
interactive programs such as text editors, debuggers, illustrators,
and shells. It has a simple syntax and is programmable, allowing Tcl
users to write command procedures to extend the built-in set of
commands. Further more, the library provides a wide range of
functions for OS abstraction and container management, which can be
used without the Tcl language itself.
Second, Tcl is a library package that can be embedded in application
programs. The Tcl library consists of a parser for the Tcl language,
routines to implement the Tcl built-in commands, and procedures that allow
applications to extend Tcl. The application program generates Tcl
commands and passes them to the Tcl parser for execution. The parser
executes built-in commands directly, and uses the call-back method for
application-specific commands.
This design allows three-tiered applications, having a middle-tier that
represents "business objects". The middle tier is the C-application, while
the third tier consists mainly of the Tcl code, which renders various views
of the business objects for the display e.g. in browsers. Embedding Tcl
gives webshell the flexibility needed in Web environments. It allows
combining state-of-the-art software engineering with the speed of HTML
publishing and separates these two development cycles.
Tcl has been ported to all major operating systems. It is easily
extensible, and Tcl extensions like webshell can profit from
third-party extensions as well. Additional functionality, e.g.,
application-specific commands written in C/C++, can be dynamically
added using shared libraries (on Unix platforms) or dynamic link
libraries (Microsoft Windows platforms). Such libraries are used, for
example, for database connectivity. This makes change management much
easier, since modules are clearly separated, ensures quick loading of
code, and does not affect a running system.
-- Environment --
webshell is a Tcl extension. It can be run as a stand-alone application,
or it can be dynamically loaded into a Tcl application. In a Web
environment, webshell is run in a CGI environment (Common Gateway
Interface) or as Apache 2 module.
webshell has been designed to ease the implementation of dynamic
content within WWW servers. There are several techniques in use to
provide such dynamic content:
==* Server-side includes (SSI): This technique is available with several
WWW servers (HTTP servers). It based on a custom extension to
HTML, which is parsed by the server whenever the corresponding
document is requested. These extensions contain directives for
conditional text and text substitution. This technique is only
suitable for applications where text substitution is possible,
that is, for simple replacements in the document. It also strongly
depends on the server software used, as there is no widely
accepted standard for the syntax. Products using this technique
include ASP or JSP.
==* Custom HTTP servers: Most off-the-shelf WWW-servers serve static
contents from a repository, which typically is a file system or a
database management system. It might make sense for some
applications to manage the HTTP-protocol themselves, i.e., to act
as custom HTTP servers, having the full freedom on how the results
of HTTP requests are returned. This technique is the most
flexible. However, there is much application overhead introduced
in properly (and efficiently) handling HTTP-requests, that this
method is only sensible for very specific applications.
==* CGI-Applications: Often dynamic content is managed using the Common
Gateway Interface (CGI). The widespread use of CGI is basically
due to its simplicity. The CGI specification relies on
POSIX-compliant execution of child processes. Parameter passing
happens via command line arguments, environment variables and
standard I/O. CGI has become the most popular technique for
dynamic content because it is standardized (not by an official
standardization body, but as an "industry-standard").
==* Embedded handlers and modules: Most current WWW server software
products support a direct extension through a specific API (e.g.,
NSAPI for Netscape products, ISAPI with Microsoft Information
Server, "modules" for Apache-based Products). This method is
probably the most efficient, since there is a tight binding
between server and extension. On the other hand, this solution is
dependent on the WWW server used. Java servlets can be considered
to fall into this category.
webshell employes the latter two techniques. Its CGI interface
ensures that webshell can be employed virtually anywhere, using
off-the-shelf web servers. If performance is key, webshell can be run
as a Apache 2 module. In this case, the server does not spend time
spawning child processes, and communication between web server and
webshell directly uses the Apache API, which is considerably faster
than in the CGI case. In addition, webshell applications can be split
into two parts, the command definition and the command call part, and
Apache 2 can keep the command definition part in memory. This
eliminates the need to re-read most parts of a webshell application
for every HTTP request, and further increases the responsivness of the
webshell application.
-- Design --
webshell is strictly modularized, particularly for thread safety. Each
module manages its own data, and locking mechanisms are used where
needed. webshell modules are extensible through plug-Ins. This
section gives an overview of the webshell modules and shortly
describes their function and design.
==D request and url management
handles input from the HTTP protocol, and state
==D session management
session data handling. On the client-side using Netscape cookies,
and on the server-side using various storage managers
(file system, data base, main-memory chache)
==D output management
sending data back to the browser
==D conversion
HTML- and URI-compliant encoding of data
==D encryption
security by strong encryption
==D messages
communication over TCP/IP sockets
==D logging
distribution of log messages
The webshell design is illustrated in [==ws3arch==].
==Figure==ws3arch==images/ws3arch.gif
webshell Design
.. request and URL management ..
The webshell application developer does not need to get involved with the
details of the HTTP protocol or the parsing of data. Rather, he
concentrates on the application logic and leaves the rest to webshell.
This module parses input from the browser, e.g. HTML form data, and makes it
available to webshell. In addition, it adds state to the HTTP protocol
using the querystring.
One of the distinctive features of webshell is its state management
capability. HTTP as a protocol is usually stateless (unless the secure
variant SSL is used). By protocol definition, there is no information
which lives from access to access. This design has many advantages, like
simple client-server application design. If state is needed, however, it
makes application development more difficult.
Web-based applications often need to carry information from one HTTP
transaction to the next. As an example, a user might have a preferred
language. Applications for electronic commerce systems, Internet
banking an so on also need mechanisms to identify and group
transactions into longer transactions which cover more than one single
HTTP request and its response. In other words, state needs to be
introduced.
Typically, there are three methods in use to identify state:
==* Encoding of state information in the URL
==* Encoding of state information in hidden form fields
==* Using Netscape Cookies.
webshell is designed to use all of these methods. However, the first is
webshells preferred method. The reason to rely mainly on the URL is that
both hidden form fields and cookies have disadvantages:
==* Hidden fields are only usable in forms. However, there are
frequently cases
where state needs to be preserved without explicitly requiring
forms. Moreover, the state might be required to be "bookmarkable"
==* Firewall setups can filter cookie information from the HTTP-stream in
order to avoid external information from entering an organization.
Also, the user can disable cookies, and not all browsers
support cookies.
URL encoding, on the other hand, has the disadvantage that it produces
somewhat long URLs. Experience has shown that the advantages more
than compensate for this drawback.
.. session context management ..
We have described above why web applications need state information.
Often, more information is needed than simply preferences. In these
cases, webshell relies on its session management module.
The session management module handles session data, which can be stored on
the client side using Netscape cookies, or on the server side using the
file system (fs), a data base management system (DBMS), or the Netcetera
cache manager (ncm). The module provides a uniform interface to access the
session context regardless of the storage used. It is implemented in Tcl
and makes extensive use of namespaces.
.. output management ..
webshell provides a set of commands to format HTTP-compliant output to
be sent back to the client. Output can be directed to Tcl channels or to
Tcl variables for buffering purposes. The technique of buffering output is
typically used to prepend additional information to the output
after the data have been processed. For example, one would like a table
of contents to a text document.
Also this module has been designed with the philosophy in mind
that the application developer does not need to
care about the details of the HTTP protocol. As an example, he does not
track whether the MIME headers have been sent or not. webshell takes care
of that.
If the developer needs control over the HTTP output, the configuration
facility of the output management module gives her full control over the
output. Of course, the output module is fully configurable, as are
all webshell modules.
.. conversion ..
Need HTML compliant input ? Want to send data via URL, or in a form
field ? The conversion module makes sure that your data are properly
formatted, converting umlauts to their proper HTML entities or their
URI encoded equivalent, for example. Like every webshell module, this
module manages its data on its own. In order to ensure thread safety,
no webshell module maintains global or static variables. Such
variables would be shared across multiple Tcl interpreters and cause
conflicts. Each time an interpreter loads webshell and thus this
module, the module-specific data like the look-up tables for the
conversions will be set up, and destroyed again when the interpreter
is deleted. The disadvantage of this design, the duplication of data
in the memory of one process, is compensated by the long-term
stability of the process resulting from clean memory management.
.. security by encryption ..
The proper handling of sensitive data is crucial for banking or
E-commerce applications. Three aspects are important: Data
transfer, data storage, and session hijacking. The first of
these aspects, data transfer, is not webshell's task. webshell
assumes that data transfer is secured whenever needed, for
example by means of SSL, and webshell deliberately chooses not
to provide any additional functionality here.
Handling of sensitive data, on the other hand, is the task of webshell
and the webshell application. This is why webshell comes with a
strong encryption sub-system to store data securely. By default,
webshell encrypts the state information in every URL it generates.
The level of security is chosen by the application developer. She
selects both the encryption method and the encryption key. For highly
sensitive data, the application developer might not even know the
pass-phrase to decrypt data from the productive environment.
webshell relies on well-known and well-tested encryption methods,
which are made available to webshell by means of plug-ins. Currently,
there are plug-Ins available for the IDEA and the blowfish encryption
methods, as well as for a simple encryption method for day-to-day use.
webshells encryption module protects data with a checksum to prevent
cipher tampering. For decryption, webshells encryption sub-system
uses a auto-detection system to determine the encryption method.
Note that webshell provides the framework to handle sensitive
data properly. The level of security, however, is determined by
the developer of a webshell application.
.. messages on streams ..
This webshell module implements a simple protocol to facilitate
message-based communication over Tcl channels. Particularly, it is
used for communication over TCP/IP connections.
.. logging facility ..
Like all service applications, web applications need a versatile
logging mechanism to report errors and state. In fact, webshell
itself makes heavy use of the logging facility. Logging must be easy
to use, fast, and extensible. Typically, webshell applications handle
hundreds of requests per second, and the logging facility has been
designed with this kind of load in mind.
The webshell logging module manages a list of filters and a list of
destinations. Each log message comes with a "address" consisting
of a tag and a level, which is compared against two filters before the
message is delivered to its destination. First, an overall filter
determines whether or not webshell needs to process the message. Then, a second,
per-destination filter determines whether or not the message has to be sent
to the log destination.
The webshell logging module is fully extensible through plug-Ins.
Out-of-the-box, webshell comes with plug-Ins to log to files, syslog,
Tcl channels, and Tcl
commands. The latter gives the application developer a simple mechanism to
extend the logging module by writing Tcl commands.
== Hello, world! ==
The following example demonstrates a very simple webshell script which
produces the simple message =/Hello, world/=
--- ------------------------------------------------------------
#!websh3
web::command default {
web::put "Hello, world!\n"
}
web::dispatch
--- ------------------------------------------------------------
This script can be used as is as a CGI application. webshell
takes care of MIME-headers and other details of the HTTP
protocol.
== Flow of control ==
The flow of control of a webshell application is as follows:
==1 Declaration and definition stage: webshell reads and evaluates
the script. The command procedures defined
by web::command and all helper procedures are not executed
immediately, however (see below).
==1 Configuration stage: Additional configuration information is
read. This happens after declaration, in order to allow specific
applications to override configuration settings and also to allow
logging parameters to be set in the declaration stage. This
allows problems in the configuration (e.g., incorrect configuration
information, configuration files cannot be accessed etc.) to be
logged accordingly.
==1 Initialization stage: Internal data structures are initialized,
depending on the type of call (e.g., as CGI-application, as
stand-alone script). If the call was as a result of an HTTP-POST
message, any HTML form data is collected. At the
end of the initialization stage, all information provided by the
client is available to the application.
==1 Command dispatch: Based on the command selector, the appropriate
web::command is executed. If there is no command selector
supplied, the default command is called.
==1 Termination stage: Application data is cleaned-up, all streams are
flushed and control is returned to the caller.
The command-dispatch stage makes it possible for one script to deal with
many actions and states of an application. For example, one script can
generate many different pages within an application. That way,
webshell programmers can keep the focus on the application as a whole,
rather than writing one script per page. This is especially important for the
somewhat special transaction characteristics of Web-applications.
In forms-based applications, a transaction, from the application's
point of view, is cut into two half-transactions. The first half
renders an HTML page with the corresponding form, while the second
part handles the data transmitted to the application. Both parts are
only glued together by the state management of webshell. However, it
is never known in advance when in time the second half of the
transaction will be executed (someone can open a form for edit and
then "forget" to submit it). The strong separation of these long
transactions into two halves is characteristic for Web-based
applications and differs from from traditional GUI applications where
both half steps, the display of a dialog and the collection of the
input, are usually executed in strong association (e.g., within the
same method of the application).
== Commands ==
This section lists the main commands of webshell. For a complete
overview, you may want to look at the
=(http://websh.com/quickref.html)(Quick Reference)=.
-- request and url management --
==* ::web::cmdurl
==* ::web::cmdurlcfg
==* ::web::dispatch
==* ::web::formvar
==* ::web::param
==* ::web::command
==* ::web::getcommand
-- session management --
==* ::web::cookiecontext
==* ::web::filecontext
==* ::web::filecounter
-- output management --
==* ::web::put
==* ::web::putx
==* ::web::putxfile
==* ::web::output
-- conversion --
==* ::web::htmlify
==* ::web::dehtmlify
==* ::web::uriencode
==* ::web::uridecode
==* ::web::ascii64
==* ::web::ascii85
-- messages --
==* ::web::send
==* ::web::recv
==* ::web::msgflag
-- encryption --
==* ::web::encrypt
==* ::web::decrypt
-- logging --
==* ::web::log
==* ::web::logdest
==* ::web::logfilter
-- misc --
==* ::web::config
==* ::web::include
==* ::web::lockfile
==* ::web::unlockfile
==* ::web::readfile
==* ::web::tempfile
==* ::web::copyright
== Security issues ==
Web-applications are subject to security issues as are all networked
applications. Furthermore, these applications are often deployed in the
Internet, making the security issues even more important. In the context
of webshell there are four different topics with the overall security
issues discussed here:
==* Can webshell applications be used to gain unauthorized
access to a computer ?
==* What levels of stability do these applications show, i.e., do webshell
applications often fail ?
==* How does webshell manage user authentication and user
authorization ?
==* How is sensitive data handeled ?
webshell does not offer any direct solution to these problems. Rather,
webshell is designed to avoid problems (intrusion, stability) and
allow simple inclusion of various authentication and data encryption
models.
The problem of gaining unauthorized access is too important to be
solved by the tool used for application development. Therefore, the
design of webshell assumes that the surrounding system architecture,
i.e., Web server and Firewall handle these issues. This means, that
the Web server is responsible to execute CGI applications with
suitable low privileges, in Unix environments typically by setting the
effective UID to an unprivileged user and executing the
CGI-application in a chroot-environment.
However, a webshell-developer can introduce security holes. The
flexibility of webshell clearly allows dangerous things to be
programmed. Therefore, security issues have to be checked with every
application.
The stability issue has rather different characteristics than the
intrusion problems, but it is nontheless very important. Unstable
applications typically "get touched" very often, leading to generally
less secure systems. Also, crashing applications can impair a system's
stability if the applications take unexpected execution paths. The
design of webshell is lead by the idea to provide a simple, flexible
and easy-to-understand framework. Compared to other products, webshell
deliberately prefers transparency over high integration and
automation. This simplicity and flexibility, somehow similar to the
Unix model, leads to a high stability of the overall system. At the
time of this writing, webshell has been in production for almost four
years, without any major stability problems so far.
User authentication is a third security domain important in many
Web-based applications. The design of webshell deliberately does not
include any specific method for user authentication. The reason for
this decision is that the specific authentication method needed
largely depends on the context of the application. Some applications
might authenticate users using a host system, others need specific
one-time-password schemes, and some applications might even rely on
authentication schemes provided by Web-servers and -browsers. The
extensibility of webshell allows various authentication schemes to be
adopted.
Finally, the importance of the secure handling of sensitive data is
becoming more and more recognized. Here, webshell provides a extensible
encryption module which allows one to easily encrypt data before
storing, and to decrypt the data after reading. For example, a simple
encryption is used by default for the querystring generation, which
might contain sensible information. The encryption module uses
checksums to ensure the full transmission of encrypted text and
timestamps in order to ensure unique data.
The encryption sub-system of webshell is easily extensible by
plug-Ins which can be loaded when needed.
== Requirements ==
Tcl 8.2.2 or higher
For use as a web application, a web server supporting CGI is
needed. The webshell module for Apache 2 requires Apache 2.
== Copyright ==
Copyright (C) 2000 by Netcetera AG.\\
All rights reserved.\\
You may always find an up-to-date version of the webshell white paper
at =(http://websh.com)=.
1.1 tcl-site/websh/whitepaper.ws3
Index: whitepaper.ws3
===================================================================
## www.websh.com/whitepaper.html
## nca-115-2
## $Id: whitepaper.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
web::response -sendheader 0
startHtmlPage
startHtmlBody
putHeader 2
web::putx {
<table border="0" cellpadding="0" cellspacing="0" width="770">
{headRow 3 "white paper"}
<tr valign="top">
{navbar_docu 1}
<td width="610">
{includeFile whitepaper.pre}
</td>
</tr>
</table>
}
finishPage 2
1.1 tcl-site/websh/whitepaper_head.txt
Index: whitepaper_head.txt
===================================================================
webshell whitepaper
Netcetera AG, Switzerland
Mar 2000
1.1 tcl-site/websh/whitepaper_pdf_head.html
Index: whitepaper_pdf_head.html
===================================================================
<html>
<head>
<title>webshell White Paper</title>
</head>
<body>
<center><h1>webshell</h1></center>
<center><h2>White Paper</h2></center>
<p>
<center>Netcetera AG, Switzerland</center>
<p>
<center>Mar 2000</center>
1.1 tcl-site/websh/ws32html.ws3
Index: ws32html.ws3
===================================================================
# -----------------------------------------------------------------------------
# ws32html.ws3 -- format websh source code for webpage
# nca-115-2
# $Id: ws32html.ws3,v 1.1 2002/05/08 10:31:09 davidw Exp $
# -----------------------------------------------------------------------------
set _keyWords {
web::put
web::putx
web::msgflag
web::putxfile
web::sessioncontextfactory
web::readfile
web::encrypt
web::truncatefile
web::config
web::recv
web::dispatch
web::encryptd
web::param
web::lockfile
web::formvar
web::list2uri
web::cmdurlcfg
web::interpclasscfg
web::unlockfile
web::htmlify
web::match
web::context
web::maineval
web::decryptd
web::cmdurl
web::command
web::filecounter
web::finalize
web::decrypt
web::finalizer
web::uri2list
web::response
web::uridecode
web::tempfile
web::request
web::send
web::logdest
web::include
web::cryptdkey
web::getcommand
web::logfilter
web::log
web::interpcfg
web::initializer
web::filecontext
web::uriencode
web::dehtmlify
web::cookiecontext
web::interp
web::interpmap
web::interpclasscfg
\w*::cset \w*::cget \w*::carray \w*::init \w*::new
after append array auto_execo auto_load auto_mkindex
auto_reset bgerror binary break case catch cd clock close concat continue
default else elseif eof error eval exec exit expr fblocked fconfigure
fcopy file fileevent filename flush for foreach format
gets glob global history http
if incr info interp join
lappend lindex linsert llength lrange lreplace lsearch lsort
library list load
memory namespace open optproc
package parray pid pkg_mkIndex proc puts pwd
read regexp registry regsub rename resource return
safe scan seek set socket source split string subst switch
tell then time trace variable
}
array set _fmt {
cmt {<font color="#800000">}
/cmt </font>
proc <b>
/proc </b>
str {<font color="#008000">}
/str </font>
var {<font color="#000080">}
/var </font>
}
# ----------------------------------------------------------------------------
# command line
# ----------------------------------------------------------------------------
if {$argc > 0 } {
set fn [lindex $argv 0]
} else {
puts stderr "fontifyws3.tcl --- usage: TBD"
exit 1
}
set fh [open $fn "r"]
puts {<pre>}
while {[eof $fh] == 0} {
set curLine [gets $fh]
## comment ?
if { [regexp {^(\s*)#} $curLine] } {
puts "$_fmt(cmt)[web::htmlify -- $curLine]$_fmt(/cmt)"
} else {
## strings (simplistic)
set str {([^\"]*)\"([^\"]*)\"(.*)}
if {[regexp $str $curLine]} {
set rest $curLine
set curLine ""
while {[regexp $str $rest dum pre tmp rest]} {
# puts "DBG rest: $rest"
append curLine [web::htmlify $pre]$_fmt(str)[web::htmlify -- \"$tmp\"]$_fmt(/str)
}
if { [string length $rest] } {
append curLine $rest
}
} else {
set curLine [web::htmlify -- $curLine]
}
## commands
set cmds (^|\[\[\{\"\;\s\])([join $_keyWords |])(\[^a-z0-9\]|$)
regsub -all $cmds $curLine \\1$_fmt(proc)\\2$_fmt(/proc)\\3 curLine
set cmds (|\[\[\{\"\;\s\])([join $_keyWords |])(\[^a-z0-9\]|)
regsub -all $cmds $curLine \\1$_fmt(proc)\\2$_fmt(/proc)\\3 curLine
## vars
set var {(^|[^\\])(\$\{[^\}]*\}|\$[a-z0-9_]+(\([^\)]*\))?)}
regsub -nocase -all $var $curLine \\1$_fmt(var)\\2$_fmt(/var) curLine
puts "$curLine"
}
}
puts {</pre>}
1.1 tcl-site/websh/buttons/b_abschluss.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_docu_a.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_docu_b.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_docu_c.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_down_a.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_down_b.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_down_c.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_prod_a.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_prod_b.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_prod_c.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_ress_a.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_ress_b.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_ress_c.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_supp_a.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_supp_b.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/b_supp_c.gif
<<Binary file>>
1.1 tcl-site/websh/buttons/pfeile.gif
<<Binary file>>
1.1 tcl-site/websh/images/ausschnitt_download.gif
<<Binary file>>
1.1 tcl-site/websh/images/ausschnitt_product.gif
<<Binary file>>
1.1 tcl-site/websh/images/ausschnitt_ressources.gif
<<Binary file>>
1.1 tcl-site/websh/images/ausschnitt_support.gif
<<Binary file>>
1.1 tcl-site/websh/images/b_ress_a.gif
<<Binary file>>
1.1 tcl-site/websh/images/b_ress_b.gif
<<Binary file>>
1.1 tcl-site/websh/images/b_ress_c.gif
<<Binary file>>
1.1 tcl-site/websh/images/bg.gif
<<Binary file>>
1.1 tcl-site/websh/images/drei.gif
<<Binary file>>
1.1 tcl-site/websh/images/drei_klein.gif
<<Binary file>>
1.1 tcl-site/websh/images/element1_navi.gif
<<Binary file>>
1.1 tcl-site/websh/images/element2_navi.gif
<<Binary file>>
1.1 tcl-site/websh/images/empty.gif
<<Binary file>>
1.1 tcl-site/websh/images/grafik_index.gif
<<Binary file>>
1.1 tcl-site/websh/images/grafik_navi.gif
<<Binary file>>
1.1 tcl-site/websh/images/grafik_navi_home.gif
<<Binary file>>
1.1 tcl-site/websh/images/grafik_strich_unten.gif
<<Binary file>>
1.1 tcl-site/websh/images/grafik_strich_unten2.gif
<<Binary file>>
1.1 tcl-site/websh/images/headline.gif
<<Binary file>>
1.1 tcl-site/websh/images/headline2.gif
<<Binary file>>
1.1 tcl-site/websh/images/logo.gif
<<Binary file>>
1.1 tcl-site/websh/images/logo_strich.gif
<<Binary file>>
1.1 tcl-site/websh/images/logo_strich2.gif
<<Binary file>>
1.1 tcl-site/websh/images/pfeil.gif
<<Binary file>>
1.1 tcl-site/websh/images/punkt_grau.gif
<<Binary file>>
1.1 tcl-site/websh/images/punkt_rot.gif
<<Binary file>>
1.1 tcl-site/websh/images/stuntFFFFFF001010.gif
<<Binary file>>
1.1 tcl-site/websh/images/uppfeil.gif
<<Binary file>>
1.1 tcl-site/websh/images/ws3arch.gif
<<Binary file>>
1.1 tcl-site/websh/images/ws3ov.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/Makefile
Index: Makefile
===================================================================
# nca-115-2
#
.SUFFIXES: .ws3 .html .syp .pre .sample
# WEBSH3 = websh3.0b3
# WEBSH3 = /home/hefti/projects/nca-073-9/src/unix/websh3.0b2p5
WEBSH3 = websh3.0b3
APACHE13 = /home/hefti/playground/installed/apache-1.3
SYP = ../../syp.tcl
WS32HTML = ../../ws32html.ws3
examples := helloworld.sample \
dispatch.sample \
logging.sample \
logging2.sample \
cookie.sample \
embed.sample \
wsp.sample \
form.sample \
encrypt.sample \
filecontext.sample
examples_html := $(examples:.sample=.html)
examples_exe := $(examples:.sample=)
images := bg.gif \
history.gif \
states.gif \
stunt.gif \
weblog.gif \
ws3arch.gif \
ws3ov.gif \
lifetime.gif \
classes.gif \
filters.gif \
idflow.gif \
transactions.gif
talk: $(examples_html) config_file.html wsphandler.html ncaintro.syp
$(WEBSH3) $(SYP) ncaintro.syp ncaintro.html -template template.html -split 1
all: talk
install: all
## examples: code
@for i in $(examples_exe); \
do \
cp $$i.sample $(APACHE13)/htdocs/$$i.ws3; \
done
mv $(APACHE13)/htdocs/wsp.ws3 $(APACHE13)/htdocs/wsp.wsp
@for i in $(images); \
do \
cp $$i $(APACHE13)/htdocs/$$i; \
done
cp start.html $(APACHE13)/htdocs
cp ncaintro*.html $(APACHE13)/htdocs
cp samples.css $(APACHE13)/htdocs
cp embed.sample $(APACHE13)/htdocs/embed.ws3
clean:
rm ncaintro*.html
rm $(examples_html)
rm config_file.html wsphandler.html
.sample.html:
@echo " == Building $@ =="
$(WEBSH3) $(WS32HTML) $< > $@
1.1 tcl-site/websh/talks/ncaintro/bg.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/classes.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/config_file.sample
Index: config_file.sample
===================================================================
web::interpclasscfg /path/to/my/shop.ws3 maxrequests 10
proc web::interpmap {f} {
if {[string match *.wsp $f]} {
return /path/to/my/wsphandler
}
return $f
}
1.1 tcl-site/websh/talks/ncaintro/cookie.sample
Index: cookie.sample
===================================================================
web::cookiecontext mycookie
web::command default {
mycookie::init cookiesample
set cnt [mycookie::cget cnt 0]
set newcnt $cnt
incr newcnt
mycookie::cset cnt $newcnt
mycookie::commit
web::put "looks like this is your visit Nr $cnt"
}
web::dispatch
1.1 tcl-site/websh/talks/ncaintro/dispatch.sample
Index: dispatch.sample
===================================================================
web::command default {
web::put "<a href=\"[web::cmdurl de]\">Hello, world !</a>"
}
web::command de {
web::put "<a href=\"[web::cmdurl ""]\">Hallo, Welt !</a>"
}
web::dispatch
1.1 tcl-site/websh/talks/ncaintro/embed.sample
Index: embed.sample
===================================================================
web::initializer {
web::put "<tt>initializing code...</tt><br>"
# open DB handle
web::command default {
web::put "<tt>"
web::put "max requests allowed for this interpreter: "
web::put "[web::interpclasscfg [web::interpcfg] maxrequests]<br>"
web::put "current request handled by this interpreter: "
web::put "[web::interpcfg numrequests]<br>"
web::put "</tt>"
}
}
web::finalizer {
# close DB handle
}
web::dispatch
1.1 tcl-site/websh/talks/ncaintro/encrypt.sample
Index: encrypt.sample
===================================================================
proc normal {msg} {
web::put "$msg<br>\n"
}
web::command default {
web::put "<a href=\"[web::cmdurl {} [list txt Hello]]\">again</a><br>\n"
web::put "<pre>[web::decrypt [web::request QUERY_STRING]]</pre><br>\n"
}
web::logfilter add *.-debug
web::logdest add *.-debug command normal
web::dispatch
1.1 tcl-site/websh/talks/ncaintro/filecontext.sample
Index: filecontext.sample
===================================================================
# setup
web::filecounter idgen -filename /tmp/SEQNR
web::filecontext mystate \
-path /tmp/demo%s.dat \
-idgen "idgen nextval" \
-attachto sid
# helpers
proc input {name size} {
return "<input type=\"text\" name=\"$name\" value=\"[web::formvar $name]\" size=\"$size\">"
}
proc submit {value} {
return "<input type=\"submit\" value=\"$value\">"
}
proc form {action code} {
web::put "<form method=\"POST\" action=\"$action\" enctype=\"multipart/form-data\">\n"
uplevel $code
web::put "</form>\n"
}
#
proc show {} {
web::formvar -set customer [mystate::cget customer "n/a"]
form [web::cmdurl save] {
web::put "session id: [mystate::id]<br>"
web::put [input customer 20]
web::put [submit "save"]
}
}
#
web::command default {
mystate::init
show
}
web::command save {
mystate::init
mystate::cset customer [web::formvar customer]
mystate::commit
show
}
web::dispatch -track sid
1.1 tcl-site/websh/talks/ncaintro/filters.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/form.sample
Index: form.sample
===================================================================
web::command default {
web::put "<form method=\"POST\" action=\"[web::cmdurl {}]\" enctype=\"multipart/form-data\">\n"
web::put "param 'user': [web::param user n/a]<br>"
web::put "<input type=\"text\" name=\"name\" value=\"[web::formvar name {n/a}]\">"
web::put "<input type=\"submit\" value=\"save\">"
web::put "</form>\n"
}
web::dispatch
1.1 tcl-site/websh/talks/ncaintro/helloworld.sample
Index: helloworld.sample
===================================================================
web::put "Hello, world !<br>"
1.1 tcl-site/websh/talks/ncaintro/history.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/httpd.conf.sample
Index: httpd.conf.sample
===================================================================
##
## httpd.conf -- Apache HTTP server configuration file
##
#
# Based upon the NCSA server configuration files originally by Rob McCool.
#
# This is the main Apache server configuration file. It contains the
# configuration directives that give the server its instructions.
# See <URL:http://www.apache.org/docs/> for detailed information about
# the directives.
#
# Do NOT simply read the instructions in here without understanding
# what they do. They're here only as hints or reminders. If you are unsure
# consult the online docs. You have been warned.
#
# After this file is processed, the server will look for and process
# /home/hefti/myprojects/installed/apache-1.3.14/conf/srm.conf and then /home/hefti/myprojects/installed/apache-1.3.14/conf/access.conf
# unless you have overridden these with ResourceConfig and/or
# AccessConfig directives here.
#
# The configuration directives are grouped into three basic sections:
# 1. Directives that control the operation of the Apache server process as a
# whole (the 'global environment').
# 2. Directives that define the parameters of the 'main' or 'default' server,
# which responds to requests that aren't handled by a virtual host.
# These directives also provide default values for the settings
# of all virtual hosts.
# 3. Settings for virtual hosts, which allow Web requests to be sent to
# different IP addresses or hostnames and have them handled by the
# same Apache server process.
#
# Configuration and logfile names: If the filenames you specify for many
# of the server's control files begin with "/" (or "drive:/" for Win32), the
# server will use that explicit path. If the filenames do *not* begin
# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
# with ServerRoot set to "/usr/local/apache" will be interpreted by the
# server as "/usr/local/apache/logs/foo.log".
#
### Section 1: Global Environment
#
# The directives in this section affect the overall operation of Apache,
# such as the number of concurrent requests it can handle or where it
# can find its configuration files.
#
#
# ServerType is either inetd, or standalone. Inetd mode is only supported on
# Unix platforms.
#
ServerType standalone
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the LockFile documentation
# (available at <URL:http://www.apache.org/docs/mod/core.html#lockfile>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
ServerRoot "/home/hefti/myprojects/installed/apache-1.3.14"
#
# The LockFile directive sets the path to the lockfile used when Apache
# is compiled with either USE_FCNTL_SERIALIZED_ACCEPT or
# USE_FLOCK_SERIALIZED_ACCEPT. This directive should normally be left at
# its default value. The main reason for changing it is if the logs
# directory is NFS mounted, since the lockfile MUST BE STORED ON A LOCAL
# DISK. The PID of the main server process is automatically appended to
# the filename.
#
#LockFile /home/hefti/myprojects/installed/apache-1.3.14/logs/httpd.lock
#
# PidFile: The file in which the server should record its process
# identification number when it starts.
#
PidFile /home/hefti/myprojects/installed/apache-1.3.14/logs/httpd.pid
#
# ScoreBoardFile: File used to store internal server process information.
# Not all architectures require this. But if yours does (you'll know because
# this file will be created when you run Apache) then you *must* ensure that
# no two invocations of Apache share the same scoreboard file.
#
ScoreBoardFile /home/hefti/myprojects/installed/apache-1.3.14/logs/httpd.scoreboard
#
# In the standard configuration, the server will process httpd.conf (this
# file, specified by the -f command line option), srm.conf, and access.conf
# in that order. The latter two files are now distributed empty, as it is
# recommended that all directives be kept in a single file for simplicity.
# The commented-out values below are the built-in defaults. You can have the
# server ignore these files altogether by using "/dev/null" (for Unix) or
# "nul" (for Win32) for the arguments to the directives.
#
#ResourceConfig conf/srm.conf
#AccessConfig conf/access.conf
#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 300
#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On
#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 100
#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 15
#
# Server-pool size regulation. Rather than making you guess how many
# server processes you need, Apache dynamically adapts to the load it
# sees --- that is, it tries to maintain enough server processes to
# handle the current load, plus a few spare servers to handle transient
# load spikes (e.g., multiple simultaneous requests from a single
# Netscape browser).
#
# It does this by periodically checking how many servers are waiting
# for a request. If there are fewer than MinSpareServers, it creates
# a new spare. If there are more than MaxSpareServers, some of the
# spares die off. The default values are probably OK for most sites.
#
MinSpareServers 0
MaxSpareServers 0
#
# Number of servers to start initially --- should be a reasonable ballpark
# figure.
#
StartServers 1
#
# Limit on total number of servers running, i.e., limit on the number
# of clients who can simultaneously connect --- if this limit is ever
# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW.
# It is intended mainly as a brake to keep a runaway server from taking
# the system with it as it spirals down...
#
MaxClients 150
#
# MaxRequestsPerChild: the number of requests each child process is
# allowed to process before the child dies. The child will exit so
# as to avoid problems after prolonged use when Apache (and maybe the
# libraries it uses) leak memory or other resources. On most systems, this
# isn't really needed, but a few (such as Solaris) do have notable leaks
# in the libraries. For these platforms, set to something like 10000
# or so; a setting of 0 means unlimited.
#
# NOTE: This value does not include keepalive requests after the initial
# request per connection. For example, if a child process handles
# an initial request and 10 subsequent "keptalive" requests, it
# would only count as 1 request towards this limit.
#
MaxRequestsPerChild 10
#
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, in addition to the default. See also the <VirtualHost>
# directive.
#
#Listen 3000
#Listen 12.34.56.78:80
#
# BindAddress: You can support virtual hosts with this option. This directive
# is used to tell the server which IP address to listen to. It can either
# contain "*", an IP address, or a fully qualified Internet domain name.
# See also the <VirtualHost> and Listen directives.
#
#BindAddress *
#
# Dynamic Shared Object (DSO) Support
#
# To be able to use the functionality of a module which was built as a DSO you
# have to place corresponding `LoadModule' lines at this location so the
# directives contained in it are actually available _before_ they are used.
# Please read the file README.DSO in the Apache 1.3 distribution for more
# details about the DSO mechanism and run `httpd -l' for the list of already
# built-in (statically linked and thus always available) modules in your httpd
# binary.
#
# Note: The order in which modules are loaded is important. Don't change
# the order below without expert advice.
#
# Example:
# LoadModule foo_module libexec/mod_foo.so
LoadModule websh_module libexec/mod_websh.so
WebshConfig /home/hefti/myprojects/installed/apache-1.3.14/conf/mod_websh_cfg.tcl
AddHandler websh .ws3
AddHandler websh .wsp
#
# ExtendedStatus controls whether Apache will generate "full" status
# information (ExtendedStatus On) or just basic information (ExtendedStatus
# Off) when the "server-status" handler is called. The default is Off.
#
#ExtendedStatus On
### Section 2: 'Main' server configuration
#
# The directives in this section set up the values used by the 'main'
# server, which responds to any requests that aren't handled by a
# <VirtualHost> definition. These values also provide defaults for
# any <VirtualHost> containers you may define later in the file.
#
# All of these directives may appear inside <VirtualHost> containers,
# in which case these default settings will be overridden for the
# virtual host being defined.
#
#
# If your ServerType directive (set earlier in the 'Global Environment'
# section) is set to "inetd", the next few directives don't have any
# effect since their settings are defined by the inetd configuration.
# Skip ahead to the ServerAdmin directive.
#
#
# Port: The port to which the standalone server listens. For
# ports < 1023, you will need httpd to be run as root initially.
#
Port 2080
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# . On SCO (ODT 3) use "User nouser" and "Group nogroup".
# . On HPUX you may not be able to use shared memory as nobody, and the
# suggested workaround is to create a user www and use that user.
# NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET)
# when the value of (unsigned)Group is above 60000;
# don't use Group nobody on these systems!
#
User nobody
Group nobody
#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed. This address appears on some server-generated pages, such
# as error documents.
#
ServerAdmin hefti@groundhog.local
#
# ServerName allows you to set a host name which is sent back to clients for
# your server if it's different than the one the program would get (i.e., use
# "www" instead of the host's real name).
#
# Note: You cannot just invent host names and hope they work. The name you
# define here must be a valid DNS name for your host. If you don't understand
# this, ask your network administrator.
# If your host doesn't have a registered DNS name, enter its IP address here.
# You will have to access it by its address (e.g., http://123.45.67.89/)
# anyway, and this will make redirections work in a sensible way.
#
# 127.0.0.1 is the TCP/IP local loop-back address, often named localhost. Your
# machine always knows itself by this address. If you use Apache strictly for
# local testing and development, you may use 127.0.0.1 as the server name.
#
#ServerName groundhog.local
#
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
DocumentRoot "/home/hefti/myprojects/installed/apache-1.3.14/htdocs"
#
# Each directory to which Apache has access, can be configured with respect
# to which services and features are allowed and/or disabled in that
# directory (and its subdirectories).
#
# First, we configure the "default" to be a very restrictive set of
# permissions.
#
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
#
# Note that from this point forward you must specifically allow
# particular features to be enabled - so if something's not working as
# you might expect, make sure that you have specifically enabled it
# below.
#
#
# This should be changed to whatever you set DocumentRoot to.
#
<Directory "/home/hefti/myprojects/installed/apache-1.3.14/htdocs">
#
# This may also be "None", "All", or any combination of "Indexes",
# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews".
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
Options Indexes FollowSymLinks MultiViews
#
# This controls which options the .htaccess files in directories can
# override. Can also be "All", or any combination of "Options", "FileInfo",
# "AuthConfig", and "Limit"
#
AllowOverride None
#
# Controls who can get stuff from this server.
#
Order allow,deny
Allow from all
</Directory>
#
# UserDir: The name of the directory which is appended onto a user's home
# directory if a ~user request is received.
#
<IfModule mod_userdir.c>
UserDir public_html
</IfModule>
#
# Control access to UserDir directories. The following is an example
# for a site where these directories are restricted to read-only.
#
#<Directory /home/*/public_html>
# AllowOverride FileInfo AuthConfig Limit
# Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
# <Limit GET POST OPTIONS PROPFIND>
# Order allow,deny
# Allow from all
# </Limit>
# <LimitExcept GET POST OPTIONS PROPFIND>
# Order deny,allow
# Deny from all
# </LimitExcept>
#</Directory>
#
# DirectoryIndex: Name of the file or files to use as a pre-written HTML
# directory index. Separate multiple entries with spaces.
#
<IfModule mod_dir.c>
DirectoryIndex index.html
</IfModule>
#
# AccessFileName: The name of the file to look for in each directory
# for access control information.
#
AccessFileName .htaccess
#
# The following lines prevent .htaccess files from being viewed by
# Web clients. Since .htaccess files often contain authorization
# information, access is disallowed for security reasons. Comment
# these lines out if you want Web visitors to see the contents of
# .htaccess files. If you change the AccessFileName directive above,
# be sure to make the corresponding changes here.
#
# Also, folks tend to use names such as .htpasswd for password
# files, so this will protect those as well.
#
<Files ~ "^\.ht">
Order allow,deny
Deny from all
</Files>
#
# CacheNegotiatedDocs: By default, Apache sends "Pragma: no-cache" with each
# document that was negotiated on the basis of content. This asks proxy
# servers not to cache the document. Uncommenting the following line disables
# this behavior, and proxies will be allowed to cache the documents.
#
#CacheNegotiatedDocs
#
# UseCanonicalName: (new for 1.3) With this setting turned on, whenever
# Apache needs to construct a self-referencing URL (a URL that refers back
# to the server the response is coming from) it will use ServerName and
# Port to form a "canonical" name. With this setting off, Apache will
# use the hostname:port that the client supplied, when possible. This
# also affects SERVER_NAME and SERVER_PORT in CGI scripts.
#
UseCanonicalName On
#
# TypesConfig describes where the mime.types file (or equivalent) is
# to be found.
#
<IfModule mod_mime.c>
TypesConfig /home/hefti/myprojects/installed/apache-1.3.14/conf/mime.types
</IfModule>
#
# DefaultType is the default MIME type the server will use for a document
# if it cannot otherwise determine one, such as from filename extensions.
# If your server contains mostly text or HTML documents, "text/plain" is
# a good value. If most of your content is binary, such as applications
# or images, you may want to use "application/octet-stream" instead to
# keep browsers from trying to display binary files as though they are
# text.
#
DefaultType text/plain
#
# The mod_mime_magic module allows the server to use various hints from the
# contents of the file itself to determine its type. The MIMEMagicFile
# directive tells the module where the hint definitions are located.
# mod_mime_magic is not part of the default server (you have to add
# it yourself with a LoadModule [see the DSO paragraph in the 'Global
# Environment' section], or recompile the server and include mod_mime_magic
# as part of the configuration), so it's enclosed in an <IfModule> container.
# This means that the MIMEMagicFile directive will only be processed if the
# module is part of the server.
#
<IfModule mod_mime_magic.c>
MIMEMagicFile /home/hefti/myprojects/installed/apache-1.3.14/conf/magic
</IfModule>
#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off
#
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog /home/hefti/myprojects/installed/apache-1.3.14/logs/error_log
#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
LogLevel warn
#
# The following directives define some format nicknames for use with
# a CustomLog directive (see below).
#
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here. Contrariwise, if you *do*
# define per-<VirtualHost> access logfiles, transactions will be
# logged therein and *not* in this file.
#
CustomLog /home/hefti/myprojects/installed/apache-1.3.14/logs/access_log common
#
# If you would like to have agent and referer logfiles, uncomment the
# following directives.
#
#CustomLog /home/hefti/myprojects/installed/apache-1.3.14/logs/referer_log referer
#CustomLog /home/hefti/myprojects/installed/apache-1.3.14/logs/agent_log agent
#
# If you prefer a single logfile with access, agent, and referer information
# (Combined Logfile Format) you can use the following directive.
#
#CustomLog /home/hefti/myprojects/installed/apache-1.3.14/logs/access_log combined
#
# Optionally add a line containing the server version and virtual host
# name to server-generated pages (error documents, FTP directory listings,
# mod_status and mod_info output etc., but not CGI generated documents).
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
# Set to one of: On | Off | EMail
#
ServerSignature On
#
# Aliases: Add here as many aliases as you need (with no limit). The format is
# Alias fakename realname
#
<IfModule mod_alias.c>
#
# Note that if you include a trailing / on fakename then the server will
# require it to be present in the URL. So "/icons" isn't aliased in this
# example, only "/icons/"..
#
Alias /icons/ "/home/hefti/myprojects/installed/apache-1.3.14/icons/"
<Directory "/home/hefti/myprojects/installed/apache-1.3.14/icons">
Options Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>
#
# ScriptAlias: This controls which directories contain server scripts.
# ScriptAliases are essentially the same as Aliases, except that
# documents in the realname directory are treated as applications and
# run by the server when requested rather than as documents sent to the client.
# The same rules about trailing "/" apply to ScriptAlias directives as to
# Alias.
#
ScriptAlias /cgi-bin/ "/home/hefti/myprojects/installed/apache-1.3.14/cgi-bin/"
#
# "/home/hefti/myprojects/installed/apache-1.3.14/cgi-bin" should be changed to whatever your ScriptAliased
# CGI directory exists, if you have that configured.
#
<Directory "/home/hefti/myprojects/installed/apache-1.3.14/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
</IfModule>
# End of aliases.
#
# Redirect allows you to tell clients about documents which used to exist in
# your server's namespace, but do not anymore. This allows you to tell the
# clients where to look for the relocated document.
# Format: Redirect old-URI new-URL
#
#
# Directives controlling the display of server-generated directory listings.
#
<IfModule mod_autoindex.c>
#
# FancyIndexing is whether you want fancy directory indexing or standard
#
IndexOptions FancyIndexing
#
# AddIcon* directives tell the server which icon to show for different
# files or filename extensions. These are only displayed for
# FancyIndexed directories.
#
AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
AddIconByType (TXT,/icons/text.gif) text/*
AddIconByType (IMG,/icons/image2.gif) image/*
AddIconByType (SND,/icons/sound2.gif) audio/*
AddIconByType (VID,/icons/movie.gif) video/*
AddIcon /icons/binary.gif .bin .exe
AddIcon /icons/binhex.gif .hqx
AddIcon /icons/tar.gif .tar
AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
AddIcon /icons/a.gif .ps .ai .eps
AddIcon /icons/layout.gif .html .shtml .htm .pdf
AddIcon /icons/text.gif .txt
AddIcon /icons/c.gif .c
AddIcon /icons/p.gif .pl .py
AddIcon /icons/f.gif .for
AddIcon /icons/dvi.gif .dvi
AddIcon /icons/uuencoded.gif .uu
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
AddIcon /icons/tex.gif .tex
AddIcon /icons/bomb.gif core
AddIcon /icons/back.gif ..
AddIcon /icons/hand.right.gif README
AddIcon /icons/folder.gif ^^DIRECTORY^^
AddIcon /icons/blank.gif ^^BLANKICON^^
#
# DefaultIcon is which icon to show for files which do not have an icon
# explicitly set.
#
DefaultIcon /icons/unknown.gif
#
# AddDescription allows you to place a short description after a file in
# server-generated indexes. These are only displayed for FancyIndexed
# directories.
# Format: AddDescription "description" filename
#
#AddDescription "GZIP compressed document" .gz
#AddDescription "tar archive" .tar
#AddDescription "GZIP compressed tar archive" .tgz
#
# ReadmeName is the name of the README file the server will look for by
# default, and append to directory listings.
#
# HeaderName is the name of a file which should be prepended to
# directory indexes.
#
# If MultiViews are amongst the Options in effect, the server will
# first look for name.html and include it if found. If name.html
# doesn't exist, the server will then look for name.txt and include
# it as plaintext if found.
#
ReadmeName README
HeaderName HEADER
#
# IndexIgnore is a set of filenames which directory indexing should ignore
# and not include in the listing. Shell-style wildcarding is permitted.
#
IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
</IfModule>
# End of indexing directives.
#
# Document types.
#
<IfModule mod_mime.c>
#
# AddEncoding allows you to have certain browsers (Mosaic/X 2.1+) uncompress
# information on the fly. Note: Not all browsers support this.
# Despite the name similarity, the following Add* directives have nothing
# to do with the FancyIndexing customization directives above.
#
AddEncoding x-compress Z
AddEncoding x-gzip gz tgz
#
# AddLanguage allows you to specify the language of a document. You can
# then use content negotiation to give a browser a file in a language
# it can understand.
#
# Note 1: The suffix does not have to be the same as the language
# keyword --- those with documents in Polish (whose net-standard
# language code is pl) may wish to use "AddLanguage pl .po" to
# avoid the ambiguity with the common suffix for perl scripts.
#
# Note 2: The example entries below illustrate that in quite
# some cases the two character 'Language' abbriviation is not
# identical to the two character 'Country' code for its country,
# E.g. 'Danmark/dk' versus 'Danish/da'.
#
# Note 3: In the case of 'ltz' we violate the RFC by using a three char
# specifier. But there is 'work in progress' to fix this and get
# the reference data for rfc1766 cleaned up.
#
# Danish (da) - Dutch (nl) - English (en) - Estonian (ee)
# French (fr) - German (de) - Greek-Modern (el)
# Italian (it) - Korean (kr) - Norwegian (no)
# Portugese (pt) - Luxembourgeois* (ltz)
# Spanish (es) - Swedish (sv) - Catalan (ca) - Czech(cz)
# Polish (pl) - Brazilian Portuguese (pt-br) - Japanese (ja)
# Russian (ru)
#
AddLanguage da .dk
AddLanguage nl .nl
AddLanguage en .en
AddLanguage et .ee
AddLanguage fr .fr
AddLanguage de .de
AddLanguage el .el
AddLanguage he .he
AddCharset ISO-8859-8 .iso8859-8
AddLanguage it .it
AddLanguage ja .ja
AddCharset ISO-2022-JP .jis
AddLanguage kr .kr
AddCharset ISO-2022-KR .iso-kr
AddLanguage no .no
AddLanguage pl .po
AddCharset ISO-8859-2 .iso-pl
AddLanguage pt .pt
AddLanguage pt-br .pt-br
AddLanguage ltz .lu
AddLanguage ca .ca
AddLanguage es .es
AddLanguage sv .se
AddLanguage cz .cz
AddLanguage ru .ru
AddLanguage tw .tw
AddCharset Big5 .Big5 .big5
AddCharset WINDOWS-1251 .cp-1251
AddCharset CP866 .cp866
AddCharset ISO-8859-5 .iso-ru
AddCharset KOI8-R .koi8-r
AddCharset UCS-2 .ucs2
AddCharset UCS-4 .ucs4
AddCharset UTF-8 .utf8
# LanguagePriority allows you to give precedence to some languages
# in case of a tie during content negotiation.
#
# Just list the languages in decreasing order of preference. We have
# more or less alphabetized them here. You probably want to change this.
#
<IfModule mod_negotiation.c>
LanguagePriority en da nl et fr de el it ja kr no pl pt pt-br ru ltz ca es sv tw
</IfModule>
#
# AddType allows you to tweak mime.types without actually editing it, or to
# make certain files to be certain types.
#
# For example, the PHP 3.x module (not part of the Apache distribution - see
# http://www.php.net) will typically use:
#
#AddType application/x-httpd-php3 .php3
#AddType application/x-httpd-php3-source .phps
#
# And for PHP 4.x, use:
#
#AddType application/x-httpd-php .php
#AddType application/x-httpd-php-source .phps
AddType application/x-tar .tgz
#
# AddHandler allows you to map certain file extensions to "handlers",
# actions unrelated to filetype. These can be either built into the server
# or added with the Action command (see below)
#
# If you want to use server side includes, or CGI outside
# ScriptAliased directories, uncomment the following lines.
#
# To use CGI scripts:
#
#AddHandler cgi-script .cgi
#
# To use server-parsed HTML files
#
#AddType text/html .shtml
#AddHandler server-parsed .shtml
#
# Uncomment the following line to enable Apache's send-asis HTTP file
# feature
#
#AddHandler send-as-is asis
#
# If you wish to use server-parsed imagemap files, use
#
#AddHandler imap-file map
#
# To enable type maps, you might want to use
#
#AddHandler type-map var
</IfModule>
# End of document types.
#
# Action lets you define media types that will execute a script whenever
# a matching file is called. This eliminates the need for repeated URL
# pathnames for oft-used CGI file processors.
# Format: Action media/type /cgi-script/location
# Format: Action handler-name /cgi-script/location
#
#
# MetaDir: specifies the name of the directory in which Apache can find
# meta information files. These files contain additional HTTP headers
# to include when sending the document
#
#MetaDir .web
#
# MetaSuffix: specifies the file name suffix for the file containing the
# meta information.
#
#MetaSuffix .meta
#
# Customizable error response (Apache style)
# these come in three flavors
#
# 1) plain text
#ErrorDocument 500 "The server made a boo boo.
# n.b. the single leading (") marks it as text, it does not get output
#
# 2) local redirects
#ErrorDocument 404 /missing.html
# to redirect to local URL /missing.html
#ErrorDocument 404 /cgi-bin/missing_handler.pl
# N.B.: You can redirect to a script or a document using server-side-includes.
#
# 3) external redirects
#ErrorDocument 402 http://some.other_server.com/subscription_info.html
# N.B.: Many of the environment variables associated with the original
# request will *not* be available to such a script.
#
# Customize behaviour based on the browser
#
<IfModule mod_setenvif.c>
#
# The following directives modify normal HTTP response behavior.
# The first directive disables keepalive for Netscape 2.x and browsers that
# spoof it. There are known problems with these browser implementations.
# The second directive is for Microsoft Internet Explorer 4.0b2
# which has a broken HTTP/1.1 implementation and does not properly
# support keepalive when it is used on 301 or 302 (redirect) responses.
#
BrowserMatch "Mozilla/2" nokeepalive
BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
#
# The following directive disables HTTP/1.1 responses to browsers which
# are in violation of the HTTP/1.0 spec by not being able to grok a
# basic 1.1 response.
#
BrowserMatch "RealPlayer 4\.0" force-response-1.0
BrowserMatch "Java/1\.0" force-response-1.0
BrowserMatch "JDK/1\.0" force-response-1.0
</IfModule>
# End of browser customization directives
#
# Allow server status reports, with the URL of http://servername/server-status
# Change the ".your_domain.com" to match your domain to enable.
#
#<Location /server-status>
# SetHandler server-status
# Order deny,allow
# Deny from all
# Allow from .your_domain.com
#</Location>
#
# Allow remote server configuration reports, with the URL of
# http://servername/server-info (requires that mod_info.c be loaded).
# Change the ".your_domain.com" to match your domain to enable.
#
#<Location /server-info>
# SetHandler server-info
# Order deny,allow
# Deny from all
# Allow from .your_domain.com
#</Location>
#
# There have been reports of people trying to abuse an old bug from pre-1.1
# days. This bug involved a CGI script distributed as a part of Apache.
# By uncommenting these lines you can redirect these attacks to a logging
# script on phf.apache.org. Or, you can record them yourself, using the script
# support/phf_abuse_log.cgi.
#
#<Location /cgi-bin/phf*>
# Deny from all
# ErrorDocument 403 http://phf.apache.org/phf_abuse_log.cgi
#</Location>
#
# Proxy Server directives. Uncomment the following lines to
# enable the proxy server:
#
#<IfModule mod_proxy.c>
# ProxyRequests On
# <Directory proxy:*>
# Order deny,allow
# Deny from all
# Allow from .your_domain.com
# </Directory>
#
# Enable/disable the handling of HTTP/1.1 "Via:" headers.
# ("Full" adds the server version; "Block" removes all outgoing Via: headers)
# Set to one of: Off | On | Full | Block
#
# ProxyVia On
#
# To enable the cache as well, edit and uncomment the following lines:
# (no cacheing without CacheRoot)
#
# CacheRoot "/home/hefti/myprojects/installed/apache-1.3.14/proxy"
# CacheSize 5
# CacheGcInterval 4
# CacheMaxExpire 24
# CacheLastModifiedFactor 0.1
# CacheDefaultExpire 1
# NoCache a_domain.com another_domain.edu joes.garage_sale.com
#</IfModule>
# End of proxy directives.
### Section 3: Virtual Hosts
#
# VirtualHost: If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them. Most configurations
# use only name-based virtual hosts so the server doesn't need to worry about
# IP addresses. This is indicated by the asterisks in the directives below.
#
# Please see the documentation at <URL:http://www.apache.org/docs/vhosts/>
# for further details before you try to setup virtual hosts.
#
# You may use the command line option '-S' to verify your virtual host
# configuration.
#
# Use name-based virtual hosting.
#
#NameVirtualHost *
#
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for requests without a known
# server name.
#
#<VirtualHost *>
# ServerAdmin webmaster@dummy-host.example.com
# DocumentRoot /www/docs/dummy-host.example.com
# ServerName dummy-host.example.com
# ErrorLog logs/dummy-host.example.com-error_log
# CustomLog logs/dummy-host.example.com-access_log common
#</VirtualHost>
1.1 tcl-site/websh/talks/ncaintro/idflow.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/lifetime.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/logging.sample
Index: logging.sample
===================================================================
web::logfilter add *.alert-debug
# web::logdest add *.alert-debug file /my/file.log
web::logdest add *.alert-debug channel [web::response]
web::put "<h1>Log Demo</h1><br>"
web::log demo.alert "a log message"
1.1 tcl-site/websh/talks/ncaintro/logging2.sample
Index: logging2.sample
===================================================================
web::logfilter add *.alert-debug
web::logdest add *.alert-error command serious
web::logdest add *.warning-debug command normal
proc serious {msg} {
web::put "<font color=\"#ff0000\">$msg</font><br>"
}
proc normal {msg} {
web::put "$msg<br>"
}
web::log demo.info "normal message"
web::log demo.alert "error message"
1.1 tcl-site/websh/talks/ncaintro/mod_websh_cfg.tcl.sample
Index: mod_websh_cfg.tcl.sample
===================================================================
web::interpclasscfg /home/hefti/myprojects/installed/apache-1.3.14/htdocs/i.ws3 maxrequests 10
web::interpclasscfg /home/hefti/myprojects/installed/apache-1.3.14/htdocs/embed.ws3 maxrequests 3
proc web::interpmap {f} {
if {[string match *.wsp $f]} {
return /home/hefti/myprojects/installed/apache-1.3.14/conf/wsp.tcl
}
return $f
}
1.1 tcl-site/websh/talks/ncaintro/ncaintro.syp
Index: ncaintro.syp
===================================================================
%%%TITLE websh3
%%%AUTHOR Simon Hefti
%%%date / company
%%%HTML <h1><center>mod_websh: a Tcl-Based Apache Module for Rapid Application Development</center></h1>
%%%HTML <br>
%%%HTML <br>
%%%HTML <h2><center>NCA-163-0</center></h2>
%%%HTML <br>
%%%HTML <br>
%%%HTML <h2><center>Simon Hefti</center></h2>
%%%HTML <h2><center>Andrej Vckovski</center></h2>
%%%HTML <h2><center>Ronnie Brunner</center></h2>
%%%HTML <br>
%%%HTML <br>
%%%HTML <br>
%%%HTML <h2><center>Netcetera AG, Zurich Switzerland</center></h2>
%%%HTML <br>
%%%HTML <h2><center>The Netcetera University, 7-Dec-2000, Zurich</center></h2>
%%%%TOC
== Agenda ==
%%%%TOC
%%%HTML <h2>1) what is webshell ?</h2>
%%%HTML <h2>2) webshell tutorial</h2>
%%%HTML <h2>3) mod_websh</h2>
%%%HTML <h2>4) porting to websh3</h2>
%%%HTML <h2>4) status</h2>
%%%HTML <h2>5) summary</h2>
== what is webshell ? ==
%%%HTML <center><b>web application development framework<br>
%%%HTML reduced to the max</b></center>
==Figure==ws3ov==ws3ov.gif
System Design
=|webshell provides|=\\
a set of commands and data structures for quick and reliable web
application development and deployment
%%%SPLIT
-- webshell is --
==D mod_websh
a dynamically loadable Apache module
==D websh3
a Tcl interpreter
==D libwebsh.so
a loadable Tcl extension
==D open source software
%%%HTML <a href="http://websh.com" target="new">http://websh.com</a>
==D quick reference
%%%HTML <a href="http://websh.com/quickref.html" target="new">http://websh.com/quickref.html</a>
%%%SPLIT
-- CGI versus embedded execution --
%%%----------------------------------------------------------------------------
==T pros | cons
%%%----------------------------------------------------------------------------
industry standard | child processes are expensive
simple, easy to debug | re-initialization of application context
robust | need pool managers for bottlenecks (DB)
might be used stand-alone |
%%%----------------------------------------------------------------------------
%%%SPLIT
-- templates versus constructive rendering --
%%%----------------------------------------------------------------------------
==T pros | cons
%%%----------------------------------------------------------------------------
straight-forward | error handling in forms complicated
simple layout design | app logic and layout tightly coupled
application programming is content management | housekeeping in yet another language
| no multi-type response (images, PDF, classes)
%%%----------------------------------------------------------------------------
==Figure==transactions==transactions.gif
HTTP and Buisness transactions
%%%SPLIT
-- the answer: webshell --
%%%HTML <center><b>webshell for everything</b></center>
==D development in CGI
use the advantages of CGI (robust, portable, stateless) for
web application development
==D deployment with mod_websh
use the advantages of embedded execution (performance)
with mod_websh
==D operation/housekeeping with websh3
use your through know-how of the development language
also to ensure operations and housekeeping
==D templates with mod_websh
complex applications: don't ASP or JSP !\\
... but use mod_websh for dynamic HTML pages
== why a new version ? ==
==D flexibility
websh3 is standard Tcl extension and can be used
as any extension and in combination with other Tcl extensions
==D portability
back-port to C for easier porting
==D mod_websh
Apache module for fast web applications
== selected features ==
==D sessions
storage independent session handling
==* group HTTP transactions into business transactions
==* session tracking
==* data attached to session
==D command dispatching
easy definition of control flow
==* URL generation including state, time stamps, and session tracking,
encrypted by default
==* automatic dispatching into various states within an application
(single binary) - jump from one page to the next within your
application
==D encryption
encrypt credit card numbers, URLs, sessions\\
==* built-in medium encryption
==* extensible on the Tcl level
==D logging
your app is live 24 hr a day, year in, year out:\\
you =/will/= need logging
==* built-in: files, channels, syslog, commands
==* extend using the "command" feature
==* clean C API additional log handlers
%%%SPLIT
-- more features --
==D buffered output
have as many output channels as you want
==D memory channels
read from and/or write to variables
==D control over output
set HTTP headers and error code, use encoding
==D versatile, transparent URL and form parameters
==* URL (=\web::param\=) and form variables (=\web::formvar\=) separated
==* handle multiple parameters with the same name
==D multi-part formdata
transparent parsing of urlencoded and multipart/formdata form data
==D request handler abstraction
commands are independent of underlying request handler - same accessor
to CGI vars in CGI case and in mod_websh
==D encoding
conversion from and to HTML code, uricoding
==D message protocol
send and receive data in platform-independent format
== webshell tutorial ==
-- hello, world --
%%%INC helloworld.html
%%%HTML <a href="/helloworld.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
%%%SPLIT
-- command dispatching --
%%%INC dispatch.html
%%%HTML <a href="/dispatch.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
%%%SPLIT
-- URL parameters and form variables (1) --
-- web::param --
==D syntax
=|web::param|= ?options? ?<key>? ?<value> ...?\\
Options are: =\-count\=, =\-set\=, =\-lappend\=, =\-names\=, and =\-unset\=
web::param is an accessor to state information from the querystring.
Suppose the querystring is "lang=EN". After web::dispatch has parsed the
querystring, =\web::param lang\= will report =\EN\=. Additionally,
web::param can manage this data and add, append, and delete parameters as
needed.
==D web::param
returns a list of all known keys
==D web::param <key> ?<default>?
returns the value for <key>. Can be a list. In case
that <key> does not exist, return <default>, if it is
given, or an empty string.
==D web::param -count <key>
returns number of items in list of <key>
==D web::param -set <key>
does the same as 'web::param <key>'
==D web::param -set <key> <value> ?<value> ...?
add the parameter <key> to the web::param data.
Any existing parameters with <key> are overwritten
==D web::param -lappend <key> <value> ?<value> ...?
append parameters with the same <key> to the web::param data. In
this case the existing <value> is not overwritten
==D web::param -unset
deletes all parameters from the web::param data
==D web::param -unset <key>
delete a parameter from the web::param data
Same (base) syntax used by:
==* web::param
==* web::formvar
==* web::cmdurlcfg
==* web::request
==* web::response
%%%SPLIT
-- URL parameters and form variables (2) --
%%%INC form.html
%%%HTML <a href="/form.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
%%%SPLIT
-- sessions (1) --
==Figure==idflow==idflow.gif
Session Id
-- state::init --
==* is id given ?
==* yes: load directly
==* no: is -attachto given ?
==* yes: is id in web::param ?
==* yes: load
==* no: is idgen given ?
==* yes: create new id and store as static param
==* no: error
==* no: error
By the way: manage static parameters using =\web::cmdurlcfg\=
%%%SPLIT
-- sessions (2) --
%%%INC cookie.html
%%%HTML <a href="/cookie.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
%%%SPLIT
-- sessions (3) --
%%%INC filecontext.html
%%%HTML <a href="/filecontext.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
%%%SPLIT
-- logging (1) --
==Figure==weblog==weblog.gif
logging
==Figure==filters==filters.gif
log filters
%%%SPLIT
-- logging (2) --
%%%INC logging.html
%%%HTML <a href="/logging.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
%%%SPLIT
-- logging (3) --
%%%INC logging2.html
%%%HTML <a href="/logging2.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
%%%SPLIT
-- encryption --
==D chains of procedures
define a list of procedures which should be tried to encrypt or decrypt
a string\\
first match is used
==D default settings
==* encryption method "D"
==* decryption: tries "plain text querystring" first, then method "D"
==D encryption method "D"
==* configurable key
==* check-sum protected (CRC-16)
%%%INC encrypt.html
%%%HTML <a href="/encrypt.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
== mod_websh ==
-- philosophy --
==D reuse interpreters
do not send time spawning a child or re-loading application logic
==D webshell script for everything
deploy =/the same/= webshell in CGI and mod_websh environments
==D template mode
if you must
==D Tcl is thread-safe - ideal for Apache 2.0
%%%SPLIT
-- architecture --
==Figure==classes==classes.gif
Object Model
%%%SPLIT
==Figure==lifetime==lifetime.gif
Life Time of Interpreters
%%%SPLIT
-- set-up --
=|httpd.conf|=\\
---
LoadModule websh_module /path/to/mod_websh.so
WebshConfig /path/to/config_file.tcl
AddHandler websh .ws3
AddHandler websh .wsp
---
=|/path/to/config_file.tcl|=\\
%%%INC config_file.html
=|/path/to/my/wsphandler|=\\
%%%INC wsphandler.html
%%%SPLIT
-- embedded execution --
%%%INC embed.html
%%%HTML <a href="http://latin:2081/embed.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo (one httpd)</a>
%%%HTML <a href="http://latin:2080/embed.ws3" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
%%%SPLIT
-- template mode --
%%%INC wsp.html
%%%HTML <a href="/wsp.wsp" onclick="javascript:window.open('','example','width=800,height=400,directories=no,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,resizable=yes');" target="example")>demo</a>
== websh2 -> websh3 ==
==D wpp_ -> web::
replacing wpp_ with web:: covers 90 % of the porting
Special:\\
==* wpp_puts -> web::put
==* wpp_eval -> web::putx
==D web::dispatch
dispatching is no longer hidden and automatically done.
You need to call web::dispatch - typically the last command
in the web app.
==D log commands
wpp_loglevel -> web::logfilter add
wpp_logrule -> web::logdest add
==D HTTP headers
==* do =|not|= use =\$env\= any longer - will not work with mod_websh.
Use =\web::request\= instead.
==* do not =\put\= HTTP header fields. Use =\web::response\= instead.
%%%SPLIT
-- mod_websh --
==D web:initializer
put code here which will be evaluated just once, when
the interpreter is created\\
Typically, this is your application bare of =\web::dispatch\=
==D web::finalizer
this code will be evaluated just before the interpreter will
be destroyed. No response to client possible here (too late).\\
Typically, close DB handles.
==D web::maineval
execute code in the controlling interpreter\\
Typically, overwrite mapper.
%%%SPLIT
-- command list --
%%%----------------------------------------------------------------------------
==T websh2 | websh3 | description
%%%----------------------------------------------------------------------------
wpp_args | n/a |
wpp_cmdurl | web::cmdurl | href for dispatch
n/a | web::cmdurlcfg | format of cmdurl
wpp_command | web::command | def a command
wpp_config | web::config | websh3 settings
n/a | web::context | cset, cget, ...
n/a | web::cookiecontext | data persistence
n/a | web::cryptdkey | encryption D key
wpp_decrypt | web::decrypt |
n/a | web::decryptd | encryption D
=/see wpp_unhtmlify/= | web::dehtmlify | remove HTML tags
n/a | web::dispatch |
wpp_encrypt | web::encrypt |
wpp_eval | =/see web::putx/= |
wpp_evalfile | =/see web::putxfile/= |
wpp_for | |
wpp_foreach | |
n/a | web::encryptd | encryption D
n/a | web::filecontext | data persistence
n/a (in wpp_state) | web::filecounter | seq nr generator
n/a | web::finalize | mod_websh compat.
n/a (mod_websh) | web::finalizer |
wpp_formvar | web::formvar | access form data
wpp_getcommand | web::getcommand |
wpp_htmlify | web::htmlify |
wpp_if | n/a |
wpp_include | web::include | source/load lib
wpp_info | n/a |
wpp_ischecked | =/see web::match/= |
wpp_isselected | =/see web::match/= |
n/a (mod_websh) | web::initializer |
n/a (mod_websh) | web::interpcfg | config of "this"
n/a (mod_websh) | web::interpclasscfg | config of class
| (web::list2uri) |
n/a | web::lockfile | lock a file
wpp_log | web::log |
wpp_logfile | =/see web::logdest/= |
wpp_loglevel | =/see web::logfilter/= |
wpp_logrule | =/see web::logdest/= |
=/see wpp_logrule/= | web::logdest | destination
=/see wpp_loglevel/= | web::logfilter | filter
n/a (mod_websh) | web::maineval | eval in controller
=/see web::isselected/= | web::match |
wpp_msgflag | web::msgflag | translate flag
wpp_output | =/see web::response/= |
wpp_param | web::param | access querystring
wpp_puts | =/see web::put/= |
=/see wpp_puts/= | web::put | write
=/see wpp_eval/= | web::putx | write and eval
=/see wpp_evalfile/= | web::putxfile | read and putx file
wpp_readfile | web::readfile |
wpp_recv | web::recv |
(env(foo)) | web::request | manage request data
=/see wpp_output/= | web::response | manage response
wpp_send | web::send |
wpp_state | =/see web::xcontext/= |
wpp_stateid | =/see web::xcontext/= |
wpp_statesave | =/see web::xcontext/= |
| (web::sessioncontextfactory)|
wpp_tempfile | web::tempfile | return unique name
wpp_unhtmlify | =/see web::dehtmlify/= |
n/a | web::truncatefile | truncate open file
n/a | web::unlockfile | unlock file
| (web::uri2list) |
wpp_uridecode | web::uridecode |
wpp_uriencode | web::uriencode |
wpp_while | n/a |
%%%----------------------------------------------------------------------------
== setting up a project ==
---
foo/
+-----------+-----------------+-----------------------+
bin/ etc/ lib/ log/
websh3* foo.conf +- libtcl8.3.so* foo.log
wrapper* foo.conf.dist +- tcl8.3/
+- init.tcl
+- encoding/
+- iso8859-1.enc
---
==D libtcl8.3.so
all Tcl 8.3.x versions are API compatible - thus you can use a
libtcl8.3.so file from any of the Tcl 8.3 releases. 8.3.2 is
preferred.
==D encoding files
==* if omitted: problems with umlauts
==* add as many as you need (Japanese ?)
== websh3 libraries ==
%%%----------------------------------------------------------------------------
==T lib | description | ws3 ready | stable
%%%----------------------------------------------------------------------------
nca-109-5/parser/parser.tcl | "AND/OR/NOT" expressions | |
nca-109-5/util/base64.tcl | conversion to and from base64 encoded strings, implemented in Tcl | y | y
nca-109-5/util/config.tcl | add cset/cget etc functionality | y | y
nca-109-5/util/context.tcl | provide command web::context for non-websh3 environment | y | y
nca-109-5/util/csv.tcl | conversion to and from M$-Excel's .csv format and Tcl lists | y | y
nca-109-5/util/text.wsh | | y | y
nca-109-5/util/version.tcl | | |
nca-109-5/util/watchdox.ws3 | watchdog | y | n
nca-109-5/util/websh2.ws3 | websh2 compatibility layer for websh3 | y | n
nca-109-5/webdb/wdb.tcl | web db driver for websh3 | y | ?
nca-109-5/webdb/db3/driver.tcl | driver for berkly db | y | ?
nca-109-5/webdb/mysql/driver.tcl | driver for mySQL | y | ?
nca-109-5/plugin/berkctx.ws3 | berkly db - based context manager for websh3 | y | ?
nca-024-8/weblib/config.wsh | =|depreciated|= | |
nca-024-8/weblib/connect.wsh | round robin connetion e.g for multiple wesams | n | y
nca-024-8/weblib/set.wsh | | |
nca-024-8/weblib/soundex.wsh | similar "sounding" words -> expression | n | y
nca-024-8/weblib/wesix.wsh | the "webshell search indexer" | n | y
nca-063-3/src/other/ftp_lib.tcl | access to ftp | |
itcl | | |
SSLtcl | | |
pdflib | | |
tclexpat | | |
tclblend | | |
| chartago/graphserver access/support | |
| exectimeout | |
| sendmail (sending e-mails from tcl) | |
| form-field validation (e-mails, integers, dates ...) | |
%%%----------------------------------------------------------------------------
== FAQ ==
==D locking
==* websh3 comes with operating-system based file locking
==* these are advisory locks
==* web::filecounter and web::filecontext are always locked
==* no "filelock.tcl" alike functionality built-in
==D is it a bug ?
==* InfoPlaza is websh3-based
==* webis is
==* netcetera.ch is
==* DVD library (and friends) are
==* websh3 is pretty stable - beta releases are in productive use since end April
==* but still: =(mailto:simon.hefti@netcetera.ch)=
==D how am I informed about websh3 ?
mail to staff
==D documentation ?
==* =(http://websh.com/quickref.html)=
==* =(http://websh.com/examples.html)=
==D open source
check out nca-073-9 and fix it
== status ==
==D beta-3
==* final API (use this version)
==* mod_websh for Apache 1.3 final
==D beta-4 issues
==* search for memory leaks
==* finalize encoding on memory channel
==* mod_websh for Apache 2.0
==* I expect it end December 2000
== summary ==
%%%HTML <center><b>web application development framework<br>
%%%HTML reduced to the max</b></center>
-- webshell is cool because --
==D it covers all aspects of web applications
CGI, mod_websh, templates
==D it has unique concepts
command dispatching\\
multiple output buffers\\
paradigm of one language for all
==D Tcl and webshell are thread safe
therefore, webshell is ready for Apache 2.0
==D it is Open Source Software
you have the code
1.1 tcl-site/websh/talks/ncaintro/runsample.ws3
Index: runsample.ws3
===================================================================
web::response -sendheader 0
web::put "<pre>\n"
set fh [open [lindex $argv 0] r]
set code [read $fh]
close $fh
# puts stderr "code: $code"
rename puts puto
proc puts {args} {
web::put [web::htmlify "==> $args"]
web::put "\n"
}
eval $code
web::put "</pre>"
1.1 tcl-site/websh/talks/ncaintro/samples.css
Index: samples.css
===================================================================
body, p, td, th, h1, h2, h3, h4, h5 {font-size:24pt;font-family:Courier,monospace,sans-serif}
h1 {font-size:28pt;margin-top:12pt;margin-bottom:10pt;}
h2 {font-size:28pt;margin-top:12pt;margin-bottom:10pt;}
h3 {font-size:24pt;}
pre {font-size:18pt;}
.nav {font-size:20pt;}
1.1 tcl-site/websh/talks/ncaintro/states.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/stunt.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/template.html
Index: template.html
===================================================================
<html>
<head>
<style type="text/css">
<!--
body, p, td, th, h1, h2, h3, h4, h5 {font-size:18pt;font-family:Courier,monospace,sans-serif}
h1 {font-size:18pt;margin-top:18pt;margin-bottom:10pt;}
h2 {font-size:18pt;margin-top:14pt;margin-bottom:10pt;}
h3 {font-size:18pt;}
pre {font-size:12pt;}
tt {font-size:12pt;}
.nav {font-size:18pt;}
.white {color:#FFFFFF}
-->
</style>
<title>webshell - in depth tutorial</title>
</head>
<body marginwidth="0" marginheight="0" topmargin="0" leftmargin="0" background="bg.gif" link="#006699" alink="red" vlink="#006699">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2"><img src="stunt.gif" border="0" width="150" height="1"></td>
<td width="20"> </td>
<td> </td>
</tr>
<tr>
<td width="5"> </td>
<td class="nav" valign="top" width="120">
%%%FIRST
%%%PREV
%%%NEXT
%%%LAST
<br><br><b>
%%%H1
</b>
</td>
<td width="20"> </td>
<td width="700" height="600" valign="top">
%%%TMPL
</td></tr>
<tr>
<td> </td>
<td class=white align="right">net</td>
<td colspan="3">
cetera
</td>
</tr>
</table>
</body>
</html>
1.1 tcl-site/websh/talks/ncaintro/transactions.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/weblog.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/ws3arch.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/ws3ov.gif
<<Binary file>>
1.1 tcl-site/websh/talks/ncaintro/wsp.sample
Index: wsp.sample
===================================================================
<html>
<head>
<title>"Webshell Server Pages"</title>
<link href="/samples.css" rel="styleSheet" type="text/css">
</head>
<body bgcolor="#ffffff">
<h1>Welcome to "Webshell Server Pages"</h1>
Local time is <%web::put [clock format [clock seconds]]%><br>
</body>
</html>
1.1 tcl-site/websh/talks/ncaintro/wsp.tcl.sample
Index: wsp.tcl.sample
===================================================================
web::config putxmarkup tag
web::putxfile [web::request SCRIPT_FILENAME]
1.1 tcl-site/websh/talks/ncaintro/wsphandler.sample
Index: wsphandler.sample
===================================================================
web::putxfile [web::request SCRIPT_FILENAME]
1.1 tcl-site/websh/titles/strich1.gif
<<Binary file>>
1.1 tcl-site/websh/titles/strich2.gif
<<Binary file>>
1.1 tcl-site/websh/titles/t_neutral.gif
<<Binary file>>
1.1 tcl-site/websh/titles/t_neutral2.gif
<<Binary file>>
1.1 tcl-site/websh/titles/t_product.gif
<<Binary file>>
---------------------------------------------------------------------
To unsubscribe, e-mail: tcl-site-cvs-unsubscribe@tcl.apache.org
For additional commands, e-mail: tcl-site-cvs-help@tcl.apache.org