| Merge. - swerc - anselm's simpler werc fork | |
| git clone git://git.suckless.org/swerc | |
| Log | |
| Files | |
| Refs | |
| README | |
| --- | |
| commit 4d495116f0456fabe7aa7988bd53819ea93faa69 | |
| parent 4f25d2da49b44924271c90ceb622de93f8f42701 | |
| Author: uriel@soma <unknown> | |
| Date: Sun, 1 Feb 2009 19:23:55 +0000 | |
| Merge. | |
| Diffstat: | |
| M apps/blagh/app.rc | 6 +++--- | |
| M apps/bridge/app.rc | 110 +++++++++++++++++++++++++----… | |
| M apps/bridge/foot.tpl | 39 ++++++++++++++++-------------… | |
| M bin/cgilib.rc | 175 ++++++-----------------------… | |
| A bin/corehandlers.rc | 115 +++++++++++++++++++++++++++++… | |
| M bin/werc.rc | 260 +++++++++--------------------… | |
| A bin/wercconf.rc | 12 ++++++++++++ | |
| A bin/werclib.rc | 117 +++++++++++++++++++++++++++++… | |
| M lib/_users/login.tpl | 6 +++--- | |
| M lib/headers.tpl | 2 +- | |
| M pub/style/style.css | 12 ++++++++++++ | |
| M sites/werc.cat-v.org/_werc/config | 2 +- | |
| 12 files changed, 482 insertions(+), 374 deletions(-) | |
| --- | |
| diff --git a/apps/blagh/app.rc b/apps/blagh/app.rc | |
| @@ -54,9 +54,9 @@ fn blagh_setup_feed_handlers { | |
| fn blagh_body { | |
| for(p in `{get_post_list $blagh_root^$blagh_dirs}) { | |
| - l=`{echo -n $p|sed 's!'$sitedir^$req_path'!!'} | |
| - sed '1s!.*!' < $p/index.md | $formatter | |
| - } | |
| + l=`{echo -n $p|sed 's!'$sitedir^$req_path'./([0-9]+/[0-9][0-9]/[0-9][0… | |
| + sed '1s!.*^') ('^$l(1)^')!' < $p/index.md | |
| + } | $formatter | |
| } | |
| fn get_post_list { | |
| diff --git a/apps/bridge/app.rc b/apps/bridge/app.rc | |
| @@ -1,30 +1,98 @@ | |
| comment_file_types=(md html) | |
| + | |
| +fn conf_enable_comments { | |
| + if(~ $1 -n) { | |
| + allow_new_user_comments=yes | |
| + shift | |
| + } | |
| + enable_comments=yes | |
| + groups_allowed_comments=$* | |
| +} | |
| + | |
| fn bridge_init { | |
| - if(! ~ $#enable_comments 0 && ! ~ `{ls $local_path.$comment_file_types >[2… | |
| - ll_add handlers_body_foot template apps/bridge/foot.tpl | |
| - if(get_post_args comment_text) { | |
| - d=`{date -n} # FIXME Obvious race | |
| - d=$local_path^'_werc/comments/'^$d/ | |
| - | |
| - u=$logged_user | |
| - if(~ $#logged_user 0) { | |
| - get_post_args comment_user_name comment_user_password | |
| - # XXX Should do this too if user not in required group | |
| - if(! login_user $comment_user_name $comment_user_password) { | |
| - u=$comment_user_name':'$comment_user_password | |
| - d=$d^'_pending' | |
| - } | |
| - if not | |
| - u = $logged_user | |
| - } | |
| + if(~ $#enable_comments 1) { | |
| + | |
| + cdir=$sitedir$req_path'_werc/comments' | |
| + if(test -d $cdir) | |
| + ll_add handlers_body_foot display_comments $cdir | |
| + | |
| + if({ check_user $groups_allowed_comments || {~ $#logged_user 0 && ! ~ … | |
| + ll_add handlers_body_foot template apps/bridge/foot.tpl | |
| + | |
| + if(~ $REQUEST_METHOD POST && mk_new_comment $cdir) | |
| + post_redirect $base_url^$post_arg_document_uri | |
| + if not | |
| + saved_comment_text=$post_arg_comment_text | |
| + } | |
| + } | |
| +} | |
| + | |
| +fn validate_new_user { | |
| + usr=$1; pass=$2; pass2=$3 | |
| + _status=() | |
| - umask 002 | |
| - if(mkdir -m 775 -p $d) { # Rudimentary perm checking | |
| - echo $u > $d/user | |
| - echo $comment_text > $d/body | |
| + if(~ $"usr '' || ! echo $usr |sed 1q|grep -s '^'$allowed_user_chars'+$') | |
| + _status='Requested user name is invalid, must match: '^$allowed_user_c… | |
| + if not if(test -d etc/users/$usr) | |
| + _status='Sorry, user name '''^$usr^''' already taken, please pick a di… | |
| + | |
| + if(~ $"pass '' || ! ~ $"pass $"pass2) | |
| + _status=($_status 'Provided passwords don''t match.') | |
| + | |
| + status=$_status | |
| +} | |
| + | |
| + | |
| +fn mk_new_comment { | |
| + _status=() | |
| + dir=$1 | |
| + if(~ $"post_arg_comment_text '') | |
| + _status='Provide a comment!' | |
| + if not if(~ $#logged_user 0) { | |
| + if(! ~ $#allow_new_user_comments 0) { | |
| + if(validate_new_user $"post_arg_comment_user $post_arg_comment_pas… | |
| + u=$post_arg_comment_user':'$post_arg_comment_passwd | |
| + dir=$cdir^'_pending' | |
| + # XXX: This doesn't work because we then do a redirect. | |
| + notify_notes='Saved comment and registration info, they will b… | |
| } | |
| + if not | |
| + _status=$status | |
| } | |
| + if not | |
| + _status='You need to log in to comment.' | |
| } | |
| + if not if(check_user $groups_allowed_comments) | |
| + u=$logged_user | |
| + if not | |
| + _status='You are not a memeber of a group allowed to comment.' | |
| + | |
| + if(~ $#_status 0) { | |
| + umask 002 | |
| + dir=$dir'/'`{date -n} # FIXME Obvious race | |
| + mkdir -m 775 -p $dir && | |
| + echo $u > $dir/user && | |
| + echo $current_date_time > $dir/posted && | |
| + echo $post_arg_comment_text > $dir/body | |
| + _s=$status | |
| + if(! ~ $"_s '') { | |
| + dprint 'ERROR XXX: Could not create comment: ' $_s | |
| + _status='Could not post comment due internal error, sorry.' | |
| + } | |
| + } | |
| + notify_errors=$_status | |
| + status=$_status | |
| } | |
| +fn display_comments { | |
| + echo '<hr /><h2>Comments</h2>' | |
| + | |
| + for(c in `{ls $*/}) { | |
| + if(test -s $c/body) { | |
| + ifs=() { echo '<div class="comment"><h5>By: <i>'`{cat $c/user}'</i… | |
| + cat $c/body | escape_html | sed 's,$,<br />,' | |
| + echo '<hr /></div>' | |
| + } | |
| + } | |
| +} | |
| diff --git a/apps/bridge/foot.tpl b/apps/bridge/foot.tpl | |
| @@ -1,26 +1,27 @@ | |
| -% cdir = $local_path^'_werc/comments' | |
| -% if(test -d $cdir) { | |
| - <hr /><h2>Comments</h2> | |
| -% for(c in `{ls $cdir/}) { | |
| - <div><b>By: <i> | |
| -% cat $c/user | |
| - </i></b> | |
| - <br /> | |
| -% cat $c/body | escape_html | sed 's,$,<br />,' | |
| - <hr /></div> | |
| -% } | |
| -% } | |
| - | |
| <hr /> | |
| +% notices_handler | |
| +% # XXX should post to bridge_post or similar | |
| <form action="" method="post"> | |
| - <textarea name="comment_text" id="comment_text" cols="80" rows="16"></text… | |
| + <textarea name="comment_text" id="comment_text" cols="80" rows="16">%($"sa… | |
| <br /> | |
| + <input type="hidden" name="document_uri" value="%($req_path%)" /> | |
| <input type="submit" name="post_comment" value="Post a comment" /> | |
| -% if(! check_user) { | |
| - <label>User: <input type="text" name="comment_user_name" value="" /></labe… | |
| - <label>Password: <input type="password" name="comment_user_password" value… | |
| - <div style="font-size: 70%">If you are not registered enter your desired u… | |
| + | |
| +% if(~ $#logged_user 0 && ! ~ $#allow_new_user_comments 0) { | |
| + <label>New user name: | |
| + <input type="text" name="comment_user" value="%($"post_arg_comment_use… | |
| + </label> | |
| + | |
| + <label>Password: | |
| + <input type="password" name="comment_passwd" value="" /> | |
| + </label> | |
| + | |
| + <label>Repeat password: | |
| + <input type="password" name="comment_passwd2" value="" /> | |
| + </label> | |
| + <div style="font-size: 70%"> | |
| + Enter your desired user name/password and after your comment has been revi… | |
| + </div> | |
| % } | |
| </form> | |
| - | |
| diff --git a/bin/cgilib.rc b/bin/cgilib.rc | |
| @@ -1,17 +1,19 @@ | |
| -############################################## | |
| -# Useful CGI functions | |
| - | |
| -NEW_LINE=' | |
| -' | |
| +# Useful CGI stuff | |
| fn dprint { echo $* >[1=2] } | |
| -fn dprintvars { { for(v in $*) { echo -n $v^'#'^$#$v^'=' $$v '; ' }; echo } >… | |
| +fn dprintv { { for(v in $*) { echo -n $v^'#'^$#$v^'=' $$v '; ' }; echo } >[1=… | |
| fn escape_html { sed 's/&/\&/g; s/</\</g; s/>/\>/g' $* } | |
| fn http_redirect { | |
| + if(~ $1 http:* https:*) | |
| + t=$1 | |
| + if not if(~ $1 /*) | |
| + t=$"base_url^$1 | |
| + if not | |
| + t=$"base_url^$"req_path^$1 | |
| echo 'Status: '^$2^' | |
| -Location: '^$1^' | |
| +Location: '^$t^' | |
| ' | |
| exit | |
| @@ -19,13 +21,6 @@ Location: '^$1^' | |
| fn perm_redirect { http_redirect $1 '301 Moved Permanantly' } | |
| fn post_redirect { http_redirect $1 '303 See Other' } | |
| -fn static_file { | |
| - echo 'Content-Type: '`{select_mime $1} | |
| - echo | |
| - cat $1 | |
| - exit | |
| -} | |
| - | |
| # Note: should check if content type is application/x-www-form-urlencoded? | |
| fn load_post_args { | |
| @@ -111,22 +106,6 @@ BEGIN { | |
| ' | |
| } | |
| -fn crop_text { | |
| - ellipsis='...' | |
| - if(~ $#* 2) | |
| - ellipsis=$2 | |
| - | |
| - awk -v max'='^$"1^' ' -v 'ellipsis='$ellipsis ' | |
| - { | |
| - nc += 1 + length; | |
| - if(nc > max) { | |
| - print substr($0, 1, nc - max) ellipsis | |
| - exit | |
| - } | |
| - }' | |
| -} | |
| - | |
| # Cookies | |
| fn set_cookie { | |
| @@ -143,6 +122,14 @@ fn get_cookie { | |
| { for(c in $co) echo $c } | sed -n 's/^ ?'$1'=//p' | |
| } | |
| + | |
| +fn static_file { | |
| + echo 'Content-Type: '`{select_mime $1} | |
| + echo | |
| + cat $1 | |
| + exit | |
| +} | |
| + | |
| fn select_mime { | |
| m='text/plain' | |
| if(~ $1 *.css) | |
| @@ -163,128 +150,30 @@ fn select_mime { | |
| ############################################## | |
| # Generic rc programming helpers | |
| +# Manage nested lists | |
| fn ll_add { | |
| _l=$1^_^$#$1 | |
| $_l=$*(2-) | |
| $1=( $$1 $_l ) | |
| } | |
| +NEW_LINE=' | |
| +' | |
| -############################################## | |
| -# Werc-specific functions | |
| - | |
| -fn get_lib_file { | |
| - if(! ~ $#sitedir 0 && test -f $sitedir/_werc/lib/$1) | |
| - echo -n $sitedir/_werc/lib/$1 | |
| - if not if(! ~ $#masterSite 0 && test -f $sitesdir/$masterSite/_werc/lib/$1) | |
| - echo -n $sitesdir/$masterSite/_werc/lib/$1 | |
| - if not if(test -f lib/$1) | |
| - echo -n lib/$1 | |
| - if not if(~ $#* 2) | |
| - echo -n $2 | |
| - if not | |
| - status='Can''t find lib file: '$1 | |
| -} | |
| - | |
| -fn template { awk -f bin/template.awk $* | rc $rcargs } | |
| - | |
| -# Auth code | |
| - | |
| -# Cookie format: WERC_USER: name:timestamp:hash(name.timestamp.password) | |
| -# login_user can't be used from a template because it sets a cookie | |
| -fn login_user { | |
| - # Note: we set the cookie even if it is already there. | |
| - if(get_user $*) | |
| - set_cookie werc_user $"logged_user^':0:'^$"logged_password | |
| -} | |
| - | |
| -# Check loggin status, if called with group arg we check membership too | |
| -fn check_user { | |
| - get_user | |
| - _status=$status | |
| - if(! ~ $#_status 0 ) | |
| - _status=(Not logged in: $"_status) | |
| - if not if(! ~ $#* 0 && ! grep -s '^'^$logged_user^'$' etc/groups/$*) { | |
| - dprint NOT IN GROUP | |
| - _status=(User $logged_user not in groups $*) | |
| - } | |
| - status=$_status | |
| -} | |
| - | |
| -# If not logged in, try to get user login info from POST or from cookie | |
| -fn get_user { | |
| - if(~ $#logged_user 0) { | |
| - if(~ $#* 2) { | |
| - user_name=$1 | |
| - user_password=$2 | |
| - } | |
| - if not if(~ $REQUEST_METHOD POST) | |
| - get_post_args user_name user_password | |
| +fn crop_text { | |
| + ellipsis='...' | |
| + if(~ $#* 2) | |
| + ellipsis=$2 | |
| - if(~ $#user_name 0) { | |
| - ifs=':' { cu=`{get_cookie werc_user|tr -d $NEW_LINE} } | |
| - if(! ~ $#cu 0) { | |
| - user_name=$cu(1) | |
| - user_password=$cu(3) | |
| - } | |
| + awk -v max'='^$"1^' ' -v 'ellipsis='$ellipsis ' | |
| + { | |
| + nc += 1 + length; | |
| + if(nc > max) { | |
| + print substr($0, 1, nc - max) ellipsis | |
| + exit | |
| } | |
| - auth_user $user_name $user_password | |
| - } | |
| - if not | |
| - status=() | |
| -} | |
| - | |
| -# Check if user_name and user_password represent a valid user account | |
| -# If valid, 'log in' by setting logged_user | |
| -fn auth_user { | |
| - user_name=$1 | |
| - user_password=$2 | |
| - | |
| - pfile='etc/users/'^$"user_name^'/password' | |
| - if(~ $#user_name 0 || ~ $#user_password 0) | |
| - status=('Auth: missing user name or pass: '^$"user_name^' / '^$"user_p… | |
| - if not if(! test -f $pfile) | |
| - status=('Auth: cant find '^$pfile) | |
| - if not if(! ~ $user_password `{cat $pfile}) | |
| - status=('Auth: Pass '$user_password' doesnt match '^`{cat $pfile}) | |
| - if not { | |
| - logged_user=$user_name | |
| - logged_password=$user_password | |
| - dprint Auth: success | |
| - status=() | |
| - } | |
| -} | |
| - | |
| -fn user_controls { | |
| - echo User: $"logged_user | |
| + }' | |
| } | |
| -# .md '(meta-)data' extract | |
| -fn get_md_file_attr { | |
| - sed -n '/^\* '$2': /p; /^\* '$2': /q; /^$/q' < $1 | |
| -} | |
| - | |
| -#app_blog_methods = ( _post index.rss ) | |
| -#fn app_blog__post { | |
| -# echo | |
| -#} | |
| -# | |
| -#app_blog___default { | |
| -# if (~ $blog) | |
| -# call_app blogpost | |
| -#} | |
| -# | |
| -## -- | |
| -#app_blogpost_methods = ( comment _edit ) | |
| -# | |
| -#fn app_blogpost_comment { | |
| -# call_app comments | |
| -#} | |
| -# | |
| -## -- | |
| -#app_comments_methods = ( _post _edit ) | |
| -# | |
| -#fn app_comments___default { | |
| -# | |
| -#} | |
| diff --git a/bin/corehandlers.rc b/bin/corehandlers.rc | |
| @@ -0,0 +1,115 @@ | |
| +# Werc builtin handlers | |
| + | |
| +fn nav_tree { | |
| + if(! ~ $#sideBarNavTitle 0) | |
| + echo '<p class="sideBarTitle">'$"sideBarNavTitle':</p>' | |
| + # Ignore stderr, last path element might be a file that doesn't exist (eg.… | |
| + # /./ to deal with p9p's ls failure to follow dir symlinks otherwise | |
| + ls -F $sitedir/./$req_paths_list >[2]/dev/null \ | |
| + | sed 's!^'$sitedir'!!; '$dirfilter'/\/[^_.\/][^\/]*(\.(md|txt|html)|\… | |
| + | sort -u | awk -F/ ' | |
| + function p(x, y, s) { for(i=0; i < x-y; i+=1) print s } | |
| + { | |
| + d = "" | |
| + if(match($0, "/$")) | |
| + d = "/" | |
| + sub("/$", "") # Strip trailing / for dirs so NF is consistent | |
| + | |
| + p(NF, lNF, "<ul class=\"side-bar\">") | |
| + p(lNF, NF, "</ul>") | |
| + lNF = NF | |
| + | |
| + bname = $NF d | |
| + path = $0 d | |
| + gsub("_", " ", bname) | |
| + | |
| + if(index(ENVIRON["req_path"] "/", path) == 1) | |
| + print "<li><a href=\"" path "\" class=\"thisPage\">»<i> " bn… | |
| + else | |
| + print "<li><a href=\"" path "\">› " bname "</a></li>" | |
| + } | |
| + END { p(lNF, 0, "</ul>") }' | |
| +} | |
| + | |
| + | |
| +fn md_handler { $formatter < $1 } | |
| + | |
| +fn tpl_handler { template $* } | |
| + | |
| +fn html_handler { | |
| + # body states: 0 = no <body> found, 2 = after <body>, 1 = after <body></bo… | |
| + awk 'gsub(".*<[Bb][Oo][Dd][Yy][^>]*>", "") > 0 {body=2} | |
| + gsub("</ *[Bb][Oo][Dd][Yy][^>]*>.*", "") > 0 {print; body=body-1} | |
| + body==2 {print} | |
| + body==0 {buf=buf "\n" $0} | |
| + END {if(body<=0) {print buf}}' < $1 | |
| +} | |
| + | |
| +fn txt_handler { | |
| + # Note: Words are not broken, even if they are way beyond 82 chars long | |
| + echo '<pre>' | |
| + sed 's/</\</g; s/>/\>/g' < $1 | fmt -l 82 -j | |
| + echo '</pre>' | |
| +} | |
| + | |
| +fn dir_listing_handler { | |
| + d=`{basename -d $1} | |
| + if(~ $#d 0) | |
| + d='/' | |
| + echo $d|sed 's,.*//,,g; s,/$,,; s,/, / ,g; s,.*,<h1 class="dir-list-head">… | |
| + # Symlinks suck: '/.' forces ls to list the linked dir if $d is a symlink. | |
| + ls -F $dir_listing_ls_opts $sitedir$d/. | sed $dirfilter$dirclean' s,.*/([… | |
| + echo '</ul>' | |
| +} | |
| + | |
| +fn notices_handler { | |
| + for(type in notify_errors notify_notes notify_success) | |
| + for(n in $$type) | |
| + echo '<div class="'$type'"><b>'$"n'</b></div>' | |
| +} | |
| + | |
| +fn setup_handlers { | |
| + | |
| + if(test -f $local_path.md) | |
| + handler_body_main=(md_handler $local_path.md) | |
| + if not if(test -f $local_path.tpl) | |
| + handler_body_main=(tpl_handler $local_path.tpl) | |
| + if not if(test -f $local_path.html) | |
| + handler_body_main=(html_handler $local_path.html) | |
| + # Global tpl (eg sitemap.tpl), should take precedence over txt handler! | |
| + if not if(test -f lib^$req_path^.tpl) | |
| + handler_body_main=(tpl_handler lib^$req_path^.tpl) | |
| + if not if(test -f $local_path.txt) | |
| + handler_body_main=(txt_handler $local_path.txt) | |
| + | |
| + # XXX Should check that $enabled_apps exist in $werc_apps? | |
| + # XXX Should split init of apps that provide main handler (eg., blog) and … | |
| + if(! ~ $#enabled_apps 0) | |
| + for(a in $enabled_apps) | |
| + $a^'_init' | |
| + | |
| + if(! ~ $#handler_body_main 0) | |
| + { } # We are done | |
| + # Dir listing | |
| + if not if(~ $local_path */index) | |
| + handler_body_main=(dir_listing_handler $req_path) | |
| + # Canonize explicit .html urls, the web server might handle this first! | |
| + if not if(~ $local_path *.html && test -f $local_path) | |
| + perm_redirect `{ echo $req_path|sed 's/.html$//' } | |
| + # Fallback static file handler | |
| + if not if(test -f $local_path) | |
| + static_file $local_path | |
| + if not if(~ $req_path /pub/* && test -f .$req_path) | |
| + static_file .$req_path | |
| + # File not found | |
| + if not { | |
| + handler_body_main=(tpl_handler `{get_lib_file 404.tpl}) | |
| + echo 'Status: 404 Not Found' | |
| + dprint 'NOT FOUND: '$SERVER_NAME^$"REQUEST_URI^' - '^$"HTTP_REFERER^' … | |
| + } | |
| +} | |
| + | |
| +fn run_handlers { for(h in $*) run_handler $$h } | |
| +fn run_handler { $*(1) $*(2-) } | |
| + | |
| + | |
| diff --git a/bin/werc.rc b/bin/werc.rc | |
| @@ -1,126 +1,17 @@ | |
| #!/usr/local/plan9/bin/rc | |
| . ./cgilib.rc | |
| +. ./werclib.rc | |
| +. ./wercconf.rc | |
| +. ./corehandlers.rc | |
| cd .. | |
| forbidden_uri_chars='[^a-zA-Z0-9_+\-\/\.]' | |
| # Expected input: ls -F style, $sitedir/path/to/files/ | |
| # <ls -F+x><symlink hack><Useless?><hiden files > | |
| -dirfilter='s/\*$//; s,/+\./+,/,g; s,^\./,,; /\/[._][^\/]/d; /'^$forbidden_uri_… | |
| +dirfilter='s/\*$//; s,/+\./+,/,g; s,^\./,,; /\/[._][^\/]/d; /'$forbidden_uri_c… | |
| dirclean=' s/\.(md|html|txt)$//; ' | |
| -# To be used from config files | |
| -fn hide_paths { | |
| - for(i in $*) | |
| - dirfilter=$dirfilter^'/^'$i'$/d; ' | |
| -} | |
| - | |
| -# Sidebar | |
| -fn nav_tree { | |
| - if(! ~ $#sideBarNavTitle 0) | |
| - echo '<p class="sideBarTitle">'$"sideBarNavTitle':</p>' | |
| - # Ignore stderr, last path element might be a file that doesn't exist (eg.… | |
| - # /./ to deal with p9p's ls failure to follow dir symlinks otherwise | |
| - ls -F $sitedir/./$req_paths_list >[2]/dev/null \ | |
| - | sed 's!^'$sitedir'!!; '^$dirfilter^'/\/[^_.\/][^\/]*(\.(md|txt|html)… | |
| - | sort -u | awk -F/ ' | |
| - function p(x, y, s) { for(i=0; i < x-y; i+=1) print s } | |
| - { | |
| - d = "" | |
| - if(match($0, "/$")) | |
| - d = "/" | |
| - sub("/$", "") # Strip trailing / for dirs so NF is consistent | |
| - | |
| - p(NF, lNF, "<ul class=\"side-bar\">") | |
| - p(lNF, NF, "</ul>") | |
| - lNF = NF | |
| - | |
| - bname = $NF d | |
| - path = $0 d | |
| - gsub("_", " ", bname) | |
| - | |
| - if(index(ENVIRON["req_path"] "/", path) == 1) | |
| - print "<li><a href=\"" path "\" class=\"thisPage\">»<i> " bn… | |
| - else | |
| - print "<li><a href=\"" path "\">› " bname "</a></li>" | |
| - } | |
| - END { p(lNF, 0, "</ul>") }' | |
| -} | |
| - | |
| - | |
| -# Handlers | |
| -fn md_handler { $formatter < $1 } | |
| - | |
| -fn tpl_handler { template $* } | |
| - | |
| -fn html_handler { | |
| - # body states: 0 = no <body> found, 2 = after <body>, 1 = after <body></bo… | |
| - awk 'gsub(".*<[Bb][Oo][Dd][Yy][^>]*>", "") > 0 {body=2} | |
| - gsub("</ *[Bb][Oo][Dd][Yy][^>]*>.*", "") > 0 {print; body=body-1} | |
| - body==2 {print} | |
| - body==0 {buf=buf "\n" $0} | |
| - END {if(body<=0) {print buf}}' < $1 | |
| -} | |
| - | |
| -fn txt_handler { | |
| - # Note: Words are not broken, even if they are way beyond 82 chars long | |
| - echo '<pre>' `{ sed 's/</\</g; s/>/\>/g' < $1 | fmt -l 82 -j } '</pr… | |
| -} | |
| - | |
| -fn dir_listing_handler { | |
| - d=`{basename -d $1} | |
| - if(~ $#d 0) | |
| - d='/' | |
| - echo $d|sed 's,.*//,,g; s,/$,,; s,/, / ,g; s,.*,<h1 class="dir-list-head">… | |
| - # Symlinks suck: '/.' forces ls to list the linked dir if $d is a symlink. | |
| - ls -F $dir_listing_ls_opts $sitedir$d/. | sed $dirfilter$dirclean' s,.*/([… | |
| - echo '</ul>' | |
| -} | |
| - | |
| -fn setup_handlers { | |
| - | |
| - if(test -f $local_path.md) | |
| - handler_body_main=(md_handler $local_path.md) | |
| - if not if(test -f $local_path.tpl) | |
| - handler_body_main=(tpl_handler $local_path.tpl) | |
| - if not if(test -f $local_path.html) | |
| - handler_body_main=(html_handler $local_path.html) | |
| - # Global tpl (eg sitemap.tpl), should take precedence over txt handler! | |
| - if not if(test -f lib^$req_path^.tpl) | |
| - handler_body_main=(tpl_handler lib^$req_path^.tpl) | |
| - if not if(test -f $local_path.txt) | |
| - handler_body_main=(txt_handler $local_path.txt) | |
| - | |
| - # XXX Should check that $enabled_apps exist in $werc_apps? | |
| - # XXX Should split init of apps that provide main handler (eg., blog) and … | |
| - if(! ~ $#enabled_apps 0) | |
| - for(a in $enabled_apps) | |
| - $a^'_init' | |
| - | |
| - if(! ~ $#handler_body_main 0) | |
| - { } # We are done | |
| - # Dir listing | |
| - if not if(~ $local_path */index) | |
| - handler_body_main=(dir_listing_handler $req_path) | |
| - # Canonize explicit .html urls, the web server might handle this first! | |
| - if not if(~ $local_path *.html && test -f $local_path) | |
| - perm_redirect `{ echo $req_path|sed 's/.html$//' } | |
| - # Fallback static file handler | |
| - if not if(test -f $local_path) | |
| - static_file $local_path | |
| - if not if(~ $req_path /pub/* && test -f .$req_path) | |
| - static_file .$req_path | |
| - # File not found | |
| - if not { | |
| - handler_body_main=(tpl_handler `{get_lib_file 404.tpl}) | |
| - echo 'Status: 404 Not Found' | |
| - dprint 'NOT FOUND: '$SERVER_NAME^$"REQUEST_URI^' - '^$"HTTP_REFERER^' … | |
| - } | |
| -} | |
| - | |
| -fn run_handlers { for(h in $*) run_handler $$h } | |
| -fn run_handler { $*(1) $*(2-) } | |
| - | |
| # Careful, the proper p9p path might not be set until initrc.local is sourced | |
| path=(. $PLAN9/bin ./bin/ /bin/ /usr/bin) | |
| @@ -130,17 +21,8 @@ ll_add handlers_bar_left nav_tree | |
| werc_apps=( apps/* ) | |
| werc_root=`{pwd} | |
| sitesdir=sites | |
| -for(i in siteTitle siteSubTitle pageTitle extraHeaders) | |
| - $i = '' | |
| - | |
| -# TODO: Per-req variables should move after initrc loading. | |
| -site=$SERVER_NAME | |
| -base_url=http://$site/ | |
| -sitedir=$sitesdir/$site | |
| -master_template=`{get_lib_file default_master.tpl} | |
| -current_date_time=`{date} | |
| -. ./etc/initrc | |
| + . ./etc/initrc | |
| if(test -f etc/initrc.local) | |
| . ./etc/initrc.local | |
| @@ -148,71 +30,83 @@ if(test -f etc/initrc.local) | |
| for(a in $werc_apps) | |
| . ./$a/app.rc | |
| -# Parse request URL | |
| -# NOTE: $REQUEST_URI is not officially in CGI 1.1, but seems to be de-facto | |
| -req_path=`{echo -n $REQUEST_URI | sed 's/\?.*//; s/'^$forbidden_uri_chars^'//g… | |
| -local_path=$sitedir$req_path | |
| -ifs='/' { args=`{echo -n $req_path} } | |
| - | |
| -# Hack: preload post data so we can access it from templates where cgi's stdin… | |
| -if(~ $REQUEST_METHOD POST) { | |
| - load_post_args | |
| - login_user | |
| -} | |
| - | |
| -if(! ~ $#args 0) | |
| - pageTitle=`{ echo $args|sed -e 's/ / - /g' -e 's/_/ /g' } | |
| +fn werc_exec_request { | |
| + site=$SERVER_NAME | |
| + base_url=http://$site | |
| + sitedir=$sitesdir/$site | |
| + master_template=`{get_lib_file default_master.tpl} | |
| + current_date_time=`{date} | |
| + | |
| + # Note: $REQUEST_URI is not officially in CGI 1.1, but seems to be de-facto | |
| + req_path=`{echo -n $REQUEST_URI | sed 's/\?.*//; s!//+!/!g; s/'^$forbidden… | |
| + local_path=$sitedir$req_path | |
| + ifs='/' { args=`{echo -n $req_path} } | |
| + | |
| + # Preload post args for templates where cgi's stdin is not accessible | |
| + if(~ $REQUEST_METHOD POST) { | |
| + load_post_args | |
| + login_user | |
| + } | |
| -if(~ $req_path */index) | |
| - perm_redirect `{echo $req_path | sed 's,/index$,/,'} | |
| + if(~ $req_path */index) | |
| + perm_redirect `{echo $req_path | sed 's,/index$,/,'} | |
| -if(~ $local_path */) { | |
| - if(test -d $local_path) | |
| - local_path=$local_path^'index' | |
| - if not # XXX: This redir might step on apps with synthetic dirs. | |
| - perm_redirect `{echo $req_path|sed 's,/+$,,'} | |
| -} | |
| -if not if(test -d $local_path) | |
| - perm_redirect $req_path^'/' | |
| - | |
| -cd $sitedir | |
| -req_paths_list='/' # Note: req_paths_list doesn't include 'stnythetic' dirs. | |
| -conf_wd='/' # Used in config files to know where we are in the document tree. | |
| -if(test -f _werc/config) | |
| - . _werc/config | |
| -for(i in $args) { | |
| - conf_wd=$conf_wd^$i | |
| - req_paths_list=($req_paths_list $conf_wd) | |
| - if(test -d $i) { | |
| - conf_wd=$conf_wd^'/' | |
| - cd $i | |
| - if(test -f _werc/config) | |
| - . _werc/config | |
| + if(~ $local_path */) { | |
| + if(test -d $local_path) | |
| + local_path=$local_path^'index' | |
| + if not # XXX: This redir might step on apps with synthetic dirs. | |
| + perm_redirect `{echo $req_path|sed 's,/+$,,'} | |
| + } | |
| + if not if(test -d $local_path) | |
| + perm_redirect $base_url^$req_path^'/' | |
| + | |
| + if(! ~ $#args 0) | |
| + pageTitle=`{ echo $args|sed -e 's/ / - /g' -e 's/_/ /g' } | |
| + | |
| + cd $sitedir | |
| + req_paths_list='/' # Note: req_paths_list doesn't include 'stnythetic' dir… | |
| + conf_wd='/' # Used in config files to know where we are in the document tr… | |
| + if(test -f _werc/config) | |
| + . _werc/config | |
| + for(i in $args) { | |
| + conf_wd=$conf_wd^$i | |
| + req_paths_list=($req_paths_list $conf_wd) | |
| + if(test -d $i) { | |
| + conf_wd=$conf_wd'/' | |
| + cd $i | |
| + if(test -f _werc/config) | |
| + . _werc/config | |
| + } | |
| + } | |
| + cd $werc_root | |
| + | |
| + f=();t=() | |
| + for(i in $perm_redir_patterns) { | |
| + if(~ $#f 0) | |
| + f=$i | |
| + if not { | |
| + t=$i | |
| + from=$base_url^$req_path | |
| + to=`{ echo $from | sed 's!'$f'!'$t'!' } | |
| + if(! ~ $to $from) | |
| + perm_redirect $to | |
| + f=() | |
| + } | |
| } | |
| -} | |
| -cd $werc_root | |
| -# Redirections and other preprocessing | |
| -if(~ $#redirectPermanent 1) { | |
| - perm_redirect $"redirectPermanent | |
| -} | |
| -if not if(~ $#redirectPermanent 2) { | |
| - from='http://'^$SERVER_NAME^$req_path | |
| - to=`{echo $from|sed 's@'^$redirectPermanent(1)^'@'^$redirectPermanent(2)^'… | |
| - if(! ~ $to $from) | |
| - perm_redirect $to | |
| -} | |
| + # Set Page title | |
| + if(~ $"pageTitle '') | |
| + pageTitle=$"siteTitle' '$"siteSubTitle | |
| + if not | |
| + pageTitle=$"pageTitle' | '$"siteTitle' '$"siteSubTitle | |
| -# Set Page title | |
| -if(~ $pageTitle '') | |
| - pageTitle=$siteTitle^' '^$siteSubTitle | |
| -if not | |
| - pageTitle=$"pageTitle^' | '^$"siteTitle^' '^$"siteSubTitle | |
| + setup_handlers | |
| -setup_handlers | |
| + if(! ~ $#debug 0) | |
| + dprint $"SERVER_NAME^$"REQUEST_URI - $"HTTP_USER_AGENT - $"REQUEST_MET… | |
| -if(! ~ $#debug 0) | |
| - dprint ' '$"SERVER_NAME^$"REQUEST_URI' - '$"HTTP_USER_AGENT' - '$"REQUEST… | |
| + template $headers $master_template #| awk_buffer | |
| + echo $res_tail | |
| +} | |
| -template $headers $master_template | awk_buffer | |
| -echo $res_tail | |
| +werc_exec_request | |
| diff --git a/bin/wercconf.rc b/bin/wercconf.rc | |
| @@ -0,0 +1,12 @@ | |
| +# To be used from config files | |
| +fn conf_perm_redirect { | |
| + if(~ $#* 1) | |
| + perm_redirect $1 | |
| + if not | |
| + perm_redir_patterns=($perm_redir_patterns $1 $2) | |
| +} | |
| + | |
| +fn conf_hide_paths { | |
| + for(i in $*) | |
| + dirfilter=$dirfilter^'/^'$i'$/d; ' | |
| +} | |
| diff --git a/bin/werclib.rc b/bin/werclib.rc | |
| @@ -0,0 +1,117 @@ | |
| +fn get_lib_file { | |
| + if(! ~ $#sitedir 0 && test -f $sitedir/_werc/lib/$1) | |
| + echo -n $sitedir/_werc/lib/$1 | |
| + if not if(! ~ $#masterSite 0 && test -f $sitesdir/$masterSite/_werc/lib/$1) | |
| + echo -n $sitesdir/$masterSite/_werc/lib/$1 | |
| + if not if(test -f lib/$1) | |
| + echo -n lib/$1 | |
| + if not if(~ $#* 2) | |
| + echo -n $2 | |
| + if not | |
| + status='Can''t find lib file: '$1 | |
| +} | |
| + | |
| +fn template { awk -f bin/template.awk $* | rc $rcargs } | |
| + | |
| +# Auth code | |
| +allowed_user_chars='[a-zA-Z0-9_]' | |
| +# Cookie format: WERC_USER: name:timestamp:hash(name.timestamp.password) | |
| +# login_user can't be used from a template because it sets a cookie | |
| +fn login_user { | |
| + # Note: we set the cookie even if it is already there. | |
| + if(get_user $*) | |
| + set_cookie werc_user $"logged_user^':0:'^$"logged_password | |
| +} | |
| + | |
| +# Check login status, if called with group arg we check membership too | |
| +fn check_user { | |
| + get_user | |
| + _status=$status | |
| + if(! ~ $"_status '') | |
| + _status=(Not logged in: $"_status) | |
| + if not if(! ~ $#* 0 && ! grep -s '^'^$logged_user^'$' etc/groups/$* etc/gr… | |
| + dprint NOT IN GROUP | |
| + _status=(User $logged_user not in groups $*) | |
| + } | |
| + status=$_status | |
| +} | |
| + | |
| +# If not logged in, try to get user login info from POST or from cookie | |
| +fn get_user { | |
| + if(~ $#logged_user 0) { | |
| + if(~ $#* 2) { | |
| + user_name=$1 | |
| + user_password=$2 | |
| + } | |
| + if not if(~ $REQUEST_METHOD POST) | |
| + get_post_args user_name user_password | |
| + | |
| + if(~ $#user_name 0) { | |
| + ifs=':' { cu=`{get_cookie werc_user|tr -d $NEW_LINE} } | |
| + if(! ~ $#cu 0) { | |
| + user_name=$cu(1) | |
| + user_password=$cu(3) | |
| + } | |
| + } | |
| + auth_user $user_name $user_password | |
| + } | |
| + if not | |
| + status=() | |
| +} | |
| + | |
| +# Check if user_name and user_password represent a valid user account | |
| +# If valid, 'log in' by setting logged_user | |
| +fn auth_user { | |
| + user_name=$1 | |
| + user_password=$2 | |
| + | |
| + pfile='etc/users/'^$"user_name^'/password' | |
| + if(~ $#user_name 0 || ~ $#user_password 0) | |
| + status=('Auth: missing user name or pass: '^$"user_name^' / '^$"user_p… | |
| + if not if(! test -f $pfile) | |
| + status=('Auth: cant find '^$pfile) | |
| + if not if(! ~ $user_password `{cat $pfile}) | |
| + status=('Auth: Pass '$user_password' doesnt match '^`{cat $pfile}) | |
| + if not { | |
| + logged_user=$user_name | |
| + logged_password=$user_password | |
| + dprint Auth: success | |
| + status=() | |
| + } | |
| +} | |
| + | |
| +fn user_controls { | |
| + echo User: $"logged_user | |
| +} | |
| + | |
| + | |
| +# .md '(meta-)data' extract | |
| +fn get_md_file_attr { | |
| + sed -n '/^\* '$2': /p; /^\* '$2': /q; /^$/q' < $1 | |
| +} | |
| + | |
| +########################################################################## | |
| +########################################################################## | |
| +#app_blog_methods = ( _post index.rss ) | |
| +#fn app_blog__post { | |
| +# echo | |
| +#} | |
| +# | |
| +#app_blog___default { | |
| +# if (~ $blog) | |
| +# call_app blogpost | |
| +#} | |
| +# | |
| +## -- | |
| +#app_blogpost_methods = ( comment _edit ) | |
| +# | |
| +#fn app_blogpost_comment { | |
| +# call_app comments | |
| +#} | |
| +# | |
| +## -- | |
| +#app_comments_methods = ( _post _edit ) | |
| +# | |
| +#fn app_comments___default { | |
| +# | |
| +#} | |
| diff --git a/lib/_users/login.tpl b/lib/_users/login.tpl | |
| @@ -5,9 +5,9 @@ | |
| % } | |
| % if not { | |
| % if (~ $REQUEST_METHOD POST) | |
| -% echo 'Login failed!' | |
| -<form method="POST"> | |
| - <label>User name: <input type="text" name="user_name" /></label><br /> | |
| +% echo '<div class="notify_errors">Login failed!</div>' | |
| +<form method="POST" style="text-align: right; float: left;"> | |
| + <label>User name: <input type="text" name="user_name" value="%($"post_arg_… | |
| <lavel>User password: <input type="password" name="user_password" /></labe… | |
| <input name="s" type="submit" value="Login" /> | |
| </form> | |
| diff --git a/lib/headers.tpl b/lib/headers.tpl | |
| @@ -27,7 +27,7 @@ Content-Type: text/html | |
| % if(! ~ $#h 0) | |
| % cat $h | |
| - %($extraHeaders%) | |
| + %($"extraHeaders%) | |
| </head> | |
| <body> | |
| diff --git a/pub/style/style.css b/pub/style/style.css | |
| @@ -334,6 +334,18 @@ blockquote { | |
| .doNotDisplay { display: none; } | |
| +.notify_errors, | |
| +.notify_notes, | |
| +.notify_success { padding: .8em; margin-bottom: 1em; border: 2px solid #ddd; } | |
| + | |
| +.notify_errors { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; } | |
| +.notify_notes { background: #FFF6BF; color: #514721; border-color: #FFD324; } | |
| +.notify_success { background: #E6EFC2; color: #264409; border-color: #C6D880; } | |
| +.notify_errors a { color: #8a1f11; } | |
| +.notify_notes a { color: #514721; } | |
| +.notify_success a { color: #264409; } | |
| + | |
| + | |
| /* # Page/Handler specific # */ | |
| h1.dir-list-head, ul.dir-list { | |
| text-transform: capitalize; | |
| diff --git a/sites/werc.cat-v.org/_werc/config b/sites/werc.cat-v.org/_werc/con… | |
| @@ -1,5 +1,5 @@ | |
| siteTitle='werc' | |
| siteSubTitle=' Bringing minimalism and sanity to the web' | |
| -enable_comments=yes | |
| +conf_enable_comments | |
| enabled_apps=($enabled_apps hello dirdir ) | |