#!/bin/bash root=src db=db sesdir=$db/session CGI="/cgi-bin/pcb-rnd-poll.cgi" if test -z "$srcdir" then srcdir="src" fi if test -z "$spiral" then spiral=/home/igor2/C/c_exp/captcha/src/captcha/main fi session_fields="SES_EMAIL SES_CAPTCHA" # how much each choice is worth when calculating scores choice2score=' BEGIN { SCORE[0] = 15 SCORE[1] = 10 SCORE[2] = 6 SCORE[3] = 3 SCORE[4] = 1 SCORE[5] = 0 } ' # ordered list of choices from 0 choices='I would use pcb-rnd in production for this feature and hereby sign up for testing the feature I hereby sign up for testing this feature in pcb-rnd I would definitely download and try pcb-rnd if it already had this feature I would maybe try pcb-rnd if it had this feature This feature is interesting, I would maybe use it in mainline, but it is not important enough for me to try pcb-rnd I do not need this feature at all ' # the same table with shorter tests choices_short='production-user tester user lurker mainliner no-need ' # someone is a tester if choice is < $tester_thrs tester_thrs=2 url_decode() { awk ' function cd(n) { chr=sprintf("%c", n); if (chr == "&") chr = "\\&" code="%" sprintf("%02x", n); CODE[tolower(code)] = chr; CODE[toupper(code)] = chr; } BEGIN { for(n = 1; n < 256; n++) cd(n); } { tmp = $0; gsub("[+]", " ", tmp); for(c in CODE) { gsub(c, CODE[c], tmp) } print tmp } ' } fix_ltgt() { sed "s//\>/g" } back_link() { echo "back to the main page" } error() { echo "Content-type: text/html" echo "" echo "

Error

" echo "$@" echo "
" back_link exit 0 } get_score() { bn=`basename $1` fn="$db/votes/$bn" if test ! -f $fn then echo "0" return fi # format: choice|email awk -F "[|]" ' (NF > 1) { choice=$1 mail=$2 VOTES[mail] = choice } '"$choice2score"' END { for(n in VOTES) score += SCORE[VOTES[n]] print score } ' < $fn } render_vote_section() { local old_ifs val n bn=$1 vote key selected # echo " $n" val=$(($val+1)) done # echo "" echo "
None of the above (remove my vote)" IFS="$old_ifs" # echo "" } do_list() { local l score name short long bn while read l do score=`get_score $l` echo "$score $l" done | sort -n -r | while read score name do bn=`basename $name` echo "" if test -f $name/icon.png then echo "" else echo " " fi short=`cat $name/short` long=`cat $name/long` echo " $score
stats" echo "[$bn]
$short$long" echo "

" if test -z "$QS_SID" then echo " start voting " else render_vote_section $bn fi done } find_all() { find "$root" -maxdepth 1 -type d -print | grep -v ".svn\|^$root\$" } find_text() { for n in `find_all` do found=`grep -- "$@" $n/short $n/long` if test ! -z "$found" then echo $n fi done } render_captcha() { if test -z "$SES_CAPTCHA" then error "INTERNAL ERROR generating the captcha" fi echo " ASCII version for the console user" echo " bitmap version for the GUI user" echo "

"
	$spiral -n 35 -aalib "$SES_CAPTCHA" | fix_ltgt | sed "s/ *$//" | grep -v "^$"
	echo "
" echo " " } cmd_captcha_jpg() { echo "Content-Type: image/jpeg" echo "" $spiral -n 35 -jpg "$SES_CAPTCHA" } render_userinfo() { if test -z "$SES_EMAIL" then echo "(anonymous visitor)" else echo "$SES_EMAIL" echo " (log out) " fi } render_vote_submit() { if test -z "$QS_SID" then return fi echo "" } render_navi1() { echo "show all" echo " | " echo "top 5 stats" } render_html() { local l if test -z "$http_hdr" then echo "Content-Type: text/html" echo "" export http_hdr=1 fi while read l do case "$l" in @\) echo "
" echo "" ;; *@form_sid*) echo "" ;; *@list*) echo "$subs_list";; *@current*) echo "$subs_current";; *@link_cgi*) echo "" ;; *@captcha*) render_captcha ;; *@userinfo*) render_userinfo;; *@vote_submit) render_vote_submit;; *@navi1*) render_navi1;; *) echo "$l" ;; esac done } rand_hex() { dd if=/dev/urandom of=/dev/stdout bs=256 count=1 2>/dev/null| md5sum | awk -v len="$1" ' { if (len == "") print $1 else print substr($1, 1, int(len)) } ' } gen_sid() { local sid n for n in 1 2 3 4 5 6 7 8 do sid=`rand_hex` if test ! -f "$sesdir/$sid" then echo "" > "$sesdir/$sid" export QS_SID="$sid" export SES_CAPTCHA=`rand_hex 6` export SES_EMAIL="" return fi done error "creating a session" } ses_save() { local n fld echo "" > "$sesdir/$QS_SID" for n in $session_fields do fld=`eval echo "\\$$n"` echo "$n $fld" >> "$sesdir/$QS_SID" done } ses_load() { local key val export QS_SID=`echo $QS_SID | tr -d -c "a-fA-F0-9"` if test ! -f "$sesdir/$QS_SID" then export QS_SID="" error "invalid SID (session id)" fi while read key val do case "$key" in SES_*) export "$key"="$val"; echo "$key=$val">&2 ;; esac done < "$sesdir/$QS_SID" } collect_votes() { local vt bn if test -z "$SES_EMAIL" then return fi export all_features=`find_all` for n in $all_features do bn=`basename $n` vt=`eval echo "\\$QS_vote_$bn"` if test ! -z "$vt" then echo "$vt|$SES_EMAIL" >> $db/votes/$bn fi done } load_votes() { local n bn declare -a -x VOTE for n in $all_features do bn=`basename $n` echo "@|$bn" cat $db/votes/$bn 2>/dev/null done | awk -v "email=$SES_EMAIL" -F "[|]" ' ($1 == "@") { name=$2; next } ($2 == email) { print name "," $1 } ' # | while read name val # do # VOTE[$name]=$val # echo "VOTE[$name]=$val and ${VOTE[windows]}" >&2 # done # echo "LAST: ${VOTE[windows]}" >&2 } cmd_enter() { export subs_current="enter voting" gen_sid render_html < $root/head.html render_html < $root/enter.html } cmd_try_enter() { local cookie email cfn uck export subs_current="entering..." if test "$QS_captcha" != "$SES_CAPTCHA" then error "you got the captcha wrong, please try again." fi export QS_email=`echo "$QS_email" | url_decode` if test -z "$QS_email" then error "you need to provide an email address to vote, please try again." fi email=`echo "$QS_email" | tr -d -c "@a-zA-Z0-9._-"` if test "$email" != "$QS_email" then error "invalid character in email the email address" fi cfn="$db/cookies/$QS_email" cookie=`cat $cfn` if test -z "$cookie" then if test ! -z "$QS_cookie" then echo "$QS_cookie" | md5sum > $cfn fi else uck=`echo "$QS_cookie" | md5sum` if test "$uck" != "$cookie" then error "wrong cookie" fi fi export SES_EMAIL="$email" echo "Content-Type: text/html" echo "" echo "Login accepted proceed." } cmd_list() { if test ! -z "$QS_find" then export subs_current="search results for $QS_find" subs_list=`find_text "$QS_find" | do_list ` else export subs_current="list all" subs_list=`find_all | do_list ` fi render_html < $root/head.html render_html < $root/index.html } cmd_logout() { echo "Content-Type: text/html" echo "" if test ! -z "$QS_SID" then if test -f "$sesdir/$QS_SID" then rm $sesdir/$QS_SID export QS_SID="" echo "Logged out. Thank you for voting." echo "
" back_link exit fi fi error "You are not logged in." } cmd_stats() { local old_ifs n not_found votes tmp export subs_current="statistics" case "$QS_fmt" in html|pie) ;; "") export QS_fmt="html";; *) error "Invalid format." esac old_ifs=$IFS IFS="+" for n in $QS_features do if test -f $root/$n/long then tmp="`cat $db/votes/$n`" votes="$votes @|$n $tmp " else not_found="$not_found $n" echo "|$n|" >&2 fi done IFS=$old_ifs if test ! -z "$not_found" then error "Features not found: $not_found" fi case "$QS_fmt" in html) render_html < $root/head.html ;; pie) echo "Content-Type: image/png" echo "";; esac echo "$votes" | awk -F "[|]" -v "choices=$choices" -v "choices_short=$choices_short" -v "qs_features=$QS_features" -v "cgi=$CGI" -v "fmt=$QS_fmt" -v "root=$root" -v "srcdir=$srcdir" ' BEGIN { HTML=1 PIE=2 if (fmt == "pie") fmt = PIE else if (fmt == "html") fmt = HTML else exit levels = split(choices, CHOICES, "[\n]")-1 split(choices_short, CHOICES_SHORT, "[\n]") COLOR[0]="#FF0000" COLOR[1]="#AA0000" COLOR[2]="#AA5500" COLOR[3]="#55AA00" COLOR[4]="#777777" COLOR[5]="#FFFFFF" } function html_tbl(TBL, divisor, feat ,n,img) { print "" print "" print "
" # header print "" print "
" if (feature != "") print "" else print " " print "    " print "" print "" feature "" print "
" load(feature, "short") "" print "
" # content img=cgi "?cmd=stats&features=" feat "&fmt=pie" for(n=0; n < levels; n++) { print "
" CHOICES_SHORT[n+1] "
" CHOICES[n+1] "

 " print "
  " int(TBL[n])/divisor "  " if (n == 0) print " " } print "
" print "
" } function pie_append(key, val) { pie = pie "\n" key "\n" val } function pie_draw(TBL) { pie="" for(n=0; n < levels; n++) { if (TBL[n] == 0) continue pie_append("@slice", TBL[n]) pie_append("@label", CHOICES_SHORT[n+1]) pie_append("@color", COLOR[n]) } print pie | "(animpie; echo screenshot \\\"/dev/stdout\\\") | animator -H -x 300 -y 200" } function load(fn, sect, tmp,l) { fn = root "/" fn "/" sect close(fn) while((getline l < fn) == 1) tmp = tmp l "\n" close(fn) return tmp } function out( u) { if (feature == "") return delete VLOCAL for(u in USER) { VLOCAL[USER[u]]++ VGLOBAL[USER[u]]++ } delete USER if (fmt == HTML) { html_tbl(VLOCAL, 1, feature) } features++ } function out_end() { feature="" if ((fmt == HTML) && (features > 1)) { print "

Average of " features " features

" html_tbl(VGLOBAL, features, qs_features) } else if (fmt == PIE) pie_draw(VGLOBAL) } ($1 == "@") { out(); feature=$2 } (NF == 2) { USER[$2]=$1 } END { out(); out_end() } ' } cmd_top_stats() { local l score name list cnt if test -z "$QS_len" then export QS_len=5 fi cnt=1 export QS_features=`find_all | while read l do score=$(get_score $l) echo "$score $l" done | sort -n -r | while read score name do basename $name cnt=$(($cnt+1)) if test $cnt -gt $QS_len then break fi done | tr "\n" "+" | sed "s/[+]$//" ` cmd_stats } ########## main ############ qs=`echo "$QUERY_STRING" | tr "&" "\n"` for n in $qs do exp="QS_$n" export $exp done if test ! -z "$QS_SID" then ses_load fi now=`date "+%m-%d %H:%M:%S.%N"` echo "$now|$QS_SID|$SES_EMAIL|$QUERY_STRING" >> $db/MASTER.log collect_votes old_votes="`load_votes`" case "$QS_cmd" in enter) cmd_enter ;; try_enter) cmd_try_enter ;; logout) cmd_logout ;; captcha) cmd_captcha_jpg;; stats) cmd_stats ;; top_stats) cmd_top_stats ;; *) cmd_list ;; esac if test ! -z "$QS_SID" then ses_save fi