#!/bin/sh
-if [ "$(COOKIE nick)" ]; then
- nickname="?$(COOKIE nick)"
-else
- nickname='?Guest'
-fi
-
if [ -f "$chatfile" ]; then
read -r channelkey x <"$chatfile"
channelkey="$( printf '%s-%s' "$channelkey" "$SESSION_ID" |sha256sum)"
fi
REDIRECT "$(URL "/$LOCATION")"
;;
- nick)
- SET_COOKIE +1209600 "nick=$(POST nickname |URL)"
- REDIRECT "$(URL "/$LOCATION")"
- ;;
- *) if [ ! -f "$chatfile" ]; then
- yield_page create <<-EOF
- [form #nonexist method=POST action="$(URL "/$LOCATION")"
- There is no channel named $(HTML "$LOCATION")
- [submit "action" "create" Create]
- ]
+esac
+
+if [ ! -f "$chatfile" ]; then
+ yield_page create <<-EOF
+ [form #nonexist method="POST"
+ There is no channel named $(HTML "$LOCATION")
+ [submit "action" "create" Create]
+ ]
EOF
- else
- { printf '
- [form #channel method=POST action="%s"
- [submit "action" "submit" style="display: none;"]
- [input type=hidden name=channelkey value="%s"]
- %s [input name="message" autofocus=true][submit "action" "submit" Send!]
- ]
- ' "$(URL "/$LOCATION")" "$channelkey" "$(settings_menu)"
- SHESCAPE='s;[]&<>#."[];\\&;g;'
+else
+ printf '%s: %s\r\n' Refresh 1
+ { printf '
+ [form #channel method="POST"
+ [submit "action" "submit" style="display: none;"]
+ [input type=hidden name=channelkey value="%s"]
+ [a .settings href="?settings#nick" Settings][input autocomplete="off" name="message" autofocus=true][submit "action" "submit" Send!]
+ ]
+ ' "$channelkey"
+ SHESCAPE='s;[]&<>#."[];\\&;g;'
- printf '[div #chat'
- # tail -n30 -f "$chatfile" | {
- # read x
- # while read -r date nick message; do
- # printf '[p .message [span .date %s] [span .nick [span .indicator %s]%s:] [span .message %s]]\n' \
- # "${date#*_}" "${nick%${nick#?}}" "$(UNSTRING "${nick#?}" |HTML)" "$(UNSTRING "$message" |HTML)"
- # done
- # }
- tail -n50 -f "$chatfile" \
- | sed -nuE '
- /^[^ ]+ [^ ]+ [^ ]+$/{
- h; s;^([^ ]+) ([^ ]+) ([^ ]+)$;\1;; s;.*_;;; s;.+;[p .message [span .date &];p;
- g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;a\2;; bESC; :A s;.;;; s;(.)(.+);[span .nick [span .indicator \1]\2];p;
- g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;b\3;; bESC; :B s;.;;; s;.+;[span .message &]];p;
- }
- b; :ESC
- '"$UNSTRING"' '"$SHESCAPE"'
- /^a/bA; /^b/bB;
- '
- } |yield_page channel
- fi
- ;;
-esac
+ while sleep 10; do printf '\n'; done &
+ printf '[div #chat'
+ tail --pid $$ -n50 -f "$chatfile" \
+ | sed -nuE '
+ /^[^ ]+ [^ ]+ [^ ]+$/{
+ h; s;^([^ ]+) ([^ ]+) ([^ ]+)$;\1;; s;.*_;;; s;.+;[p .message [span .date &];p;
+ g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;a\2;; bESC; :A s;.;;; s;(.)(.+);[span .nick [span .indicator \1]\2];p;
+ g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;b\3;; bESC; :B s;.;;; s;.+;[span .message &]];p;
+ }
+ b; :ESC
+ '"$UNSTRING"' '"$SHESCAPE"'
+ /^a/bA; /^b/bB;
+ '
+ } |yield_page channel
+fi
[title Webchat]
] [body class="%s"
' "$page"
+ [ "$QUERY_STRING" = settings ] && settings_menu
cat
printf '] ]'
} |"$_EXEC/cgilite/html-sh.sed" -u
settings_menu(){
printf '
- [input #check_settings type="checkbox"][label for=check_settings Settings]
- [div #settings
- [h1 Settings][label for=check_settings Close]
- [input #set_nick type=radio name="setting" value="nick" selected][label for=set_nick Nickname]
- [div [input name="nickname" value="%s"][submit "action" "nick" Set Cookie]]
- ]
+ [form #settings method="POST" action="?"
+ [h1 Settings][a .settings href="?" Close]'
+ printf '
+ [a .section href="#nick" Nickname]
+ [div #nick [input name="nickname" value="%s"][submit "action" "nick" Set Cookie]]
' "$(HTML "${nickname#\?}")"
+ printf '
+ [a .section href="#register" Register Nickname]
+ [div #register
+ [p Registration will set a permanent Cookie in your Browser.
+ Registration requires neither a password, nor an email address.]
+ [input name="regnick" value="%s"][submit "action" "register" Register]
+ ]' "$(HTML "${nickname#\?}")"
+ printf ']'
}
+. "$_EXEC/usernick.sh"
+
case ${LOCATION} in
- \&?*) chatfile="$_DATA/${LOCATION}"
- . $_EXEC/channel.sh
- exit 0
- ;;
- @?*) if [ -d "$_DATA/${LOCATION}" ]; then
- chatfile="$_DATA/${LOCATION}/?${SESSION_ID}"
- . $_EXEC/channel.sh
- else
- REDIRECT /
- fi
- exit 0
- ;;
- ~?*) if [ -d "$_DATA/@${LOCATION#~}" ]; then
- pubinfo="$_DATA/@${LOCATION#~}/pubinfo"
- page=pubinfo
- else
- REDIRECT /
- fi
- ;;
webchat.css)
- . "$_EXEC/file.sh"
+ . "$_EXEC/cgilite/file.sh"
FILE "$_EXEC/webchat.css"
exit 0
;;
- '') page=front;;
- *) REDIRECT /;;
-esac
-
-case "$page $(POST action)" in
- pubinfo\ *);;
- front\ *) yield_page front <<-EOF
+ \&?*)
+ chatfile="$_DATA/${LOCATION}"
+ . "$_EXEC/channel.sh"
+ exit 0
+ ;;
+ @?*)
+ if [ -d "$_DATA/${LOCATION}" ]; then
+ chatfile="$_DATA/${LOCATION}/?${SESSION_ID}"
+ . "$_EXEC/channel.sh"
+ else
+ REDIRECT /
+ fi
+ exit 0
+ ;;
+ ~?*)
+ if [ -d "$_DATA/@${LOCATION#~}" ]; then
+ pubinfo="$_DATA/@${LOCATION#~}/pubinfo"
+ else
+ REDIRECT /
+ fi
+ ;;
+ '') yield_page front <<-EOF
Front
EOF
;;
+ *) REDIRECT /
+ ;;
esac
--- /dev/null
+#!/bin/sh
+
+UNAME_VALID='
+ # Remove trailing CR, which may have been added by browser
+ s;\r$;;;
+ # Collapse white spaces
+ s;[\r\t\n ]+; ;;
+ # Remove starting and trailing white spaces
+ s;^ ;;; s; $;;;
+ # Usernames starting with & # ? @ + will be invalid
+ /^[&#?@+]/d;
+ # Usernames containing a / will be invalid
+ /\//d;
+ # Usernames must be between 3 and 24 characters
+ /...+/!d; /.{25}/d;
+ # Usernames may not span multiple lines
+ q;'
+username(){
+ { [ $# -eq 0 ] && cat || printf %s "$*"; } \
+ | sed -E ':X; $!{N;bX;}'"$UNAME_VALID"
+}
+
+nickname="$(COOKIE nick |username)"
+if [ ! "$nickname" ]; then
+ nickname='?Guest'
+elif [ ! -d "$_DATA/@$nickname" ]; then
+ nickname="?$nickname"
+else
+ userclient="$(COOKIE user_client)"
+ secuid="$(cat "$_DATA/@$nickname/secuid")"
+ clientid="${userclient%%-*}"
+ clientid="${clientid}-$(printf '%s%s' "${clientid}" "${secuid}" |sha256sum)"
+ clientid="${clientid%% *}"
+ if [ "$clientid" = "$userclient" ]; then
+ nickname=" $nickname"
+ SET_COOKIE +"$((86400 * 365))" "user_client=${clientid}" HttpOnly
+ SET_COOKIE +"$((86400 * 365))" "nick=$(URL "${nickname}")"
+ else
+ nickname='?Guest'
+ fi
+fi
+
+case $(POST action) in
+ nick)
+ nick="$(POST nickname |username)"
+ if [ ! -d "$_DATA/@$nick" ]; then
+ SET_COOKIE +1209600 "nick=$(POST nickname |URL)"
+ REDIRECT "$(URL "/$LOCATION")"
+ else
+ # ToDo: Return Error Message
+ REDIRECT "$(URL "/$LOCATION")?settings#nick"
+ fi
+ ;;
+ register)
+ regnick="$(POST regnick |username)"
+ userdir="$_DATA/@${regnick}"
+ if [ "$regnick" ] && mkdir "$userdir"; then
+ secuid="$(randomid)"; clientid="$(randomid)"
+ printf %s\\n "$secuid" >"${userdir}/secuid"
+ clientid="${clientid}-$(printf '%s%s' "${clientid}" "${secuid}" |sha256sum |cut -d\ -f1)"
+ SET_COOKIE +"$((86400 * 365))" "user_client=${clientid}" HttpOnly
+ SET_COOKIE +"$((86400 * 365))" "nick=$(URL "${regnick}")"
+ REDIRECT "$(URL "/$LOCATION")"
+ else
+ # ToDo: Return Error Message
+ REDIRECT "$(URL "/$LOCATION")?settings#register"
+ fi
+ ;;
+esac
* {
box-sizing: border-box;
- background-color: #FFF;
- color: #000;
font: normal normal normal medium/1.25 Sans-Serif;
font: normal normal normal normal medium/1.25 Sans-Serif;
text-decoration: none;
margin: 0; padding: 0;
border: none;
+ color: inherit;
}
-#chat {
- position: fixed;
- bottom: 2.5em;
- left: 0; right: 0;
- border: 1px solid #08b;
- padding: 1ex;
- margin: .5ex;
- z-index: -1;
-}
-form#channel {
- position: fixed;
- bottom: 0;
- left: 0; right: 0;
+body {
+ background-color: #FFF;
+ color: #000;
}
-#check_settings { display: none; }
-#check_settings + label {
- display: inline-block;
+b, strong { font-weight: bold; }
+i, em { font-style: italic; }
+
+input[type=text], input:not([type]) {
+ border: 1px solid #08b;
+ padding: .125ex .5ex;
}
-#check_settings + label:before {
- content: '\2699';
- padding: .5ex;
- margin-left: .5ex;
- margin-right: 2em;
+button {
+ border: outset #DDD;
+ padding: .125ex 1ex;
+ background-color: #EEE;
}
-#check_settings + label + #settings { display: none; }
-#check_settings:checked + label + #settings {
+
+#settings {
display: block;
position: fixed;
min-width: 20%; max-width: 90%;
border-bottom: 1px solid;
border-radius: 1ex 1ex 0 0;
}
-#settings label[for=check_settings] {
+#settings a.settings {
position: absolute;
top: 0; right: 1px;
background-color: #F88;
width: 3ex;
overflow: hidden;
}
-#settings label[for=check_settings]:before {
+#settings a.settings:before {
content: "x";
padding: 0 1ex;
}
-#settings input[type=radio] { display: none; }
-#settings input[type=radio] + label + * { display: none; }
-#settings input[type=radio]:checked + label + * { display: block; }
-#settings input[type=radio] + label {
+#settings a.section {
display: block;
font-weight: bold;
text-decoration: underline;
- margin: -1px 1px; padding: 0 1ex;
+ margin: -1px 1px 0 0; padding: .5ex 1ex;
border-top: 1px solid;
background-color: #EEE;
}
-#settings input[type=radio] + label + * {
+#settings a.section + * {
+ display: block;
+ padding: .5ex 1ex 0 1ex;
+ max-height: .5ex;
+ overflow: hidden;
+ transition: max-height .5s;
+}
+#settings a.section + *:target {
+ max-height: 20ex;
padding: 1ex 1ex .5ex 1ex;
}
+#settings input {margin-right: 1ex;}
+form#channel {
+ position: fixed;
+ bottom: 1ex;
+ left: .5ex; right: .5ex;
+}
+form#channel a.settings {
+ display: inline-block;
+}
+form#channel a.settings:before {
+ content: '\2699';
+ padding: 0 .75ex;
+ margin-left: .5ex;
+ margin-right: 2em;
+}
form#channel input[name=message] {
display: inline-block;
position: absolute;
- left: 4.5ex;
- width: calc(100% - 5ex - 1px);
+ right: 0;
+ width: calc(100% - 4.5ex);
}
form#channel button[value=submit] { display: none; }
#chat .message .date {
color: #888;
font-size: .75em;
}
+
+#chat {
+ position: fixed;
+ bottom: 2em;
+ left: 0; right: 0;
+ border: 1px solid #08b;
+ padding: 1ex;
+ margin: .5ex;
+ z-index: -1;
+}
+
#chat .message .nick {
font-weight: bold;
}
+
#chat .message .nick .indicator {
color: #888;
}