yuuji@0: #!/bin/sh
yuuji@0: # Here's global variable table. Do not use this names.
yuuji@1: # $HGid$
yuuji@26:
yuuji@26: [ -f s4-config.sh ] && . ./s4-config.sh
yuuji@26:
yuuji@0: myname=`basename ${SCRIPT_NAME:-$0}`
yuuji@0: mydir=`dirname ${SCRIPT_FILENAME:-$0}`
yuuji@0: myargs="$@"
yuuji@8: PATH=/usr/local/sqlite3/bin:/usr/local/vim7/bin:/usr/iekei/ImageMagick/bin:/usr/local/ImageMagick/bin:$PATH
yuuji@0: tmpdir=${TMPDIR:-tmp}
yuuji@2: dbdir=${DBDIR:-db}
yuuji@0: tmpfiles=""
yuuji@2: db=${DB:-$dbdir/cgi.sq3}
yuuji@83: admin=${ADMIN:-hostmaster@example.org}
yuuji@3: templ=${TEMPL:-templ}
yuuji@67: layout=${LAYOUT:-$templ/default}
yuuji@67: formdir=${FORMDIR:-$templ/form}
yuuji@67: imgdir=${IMGDIR:-img}
yuuji@16: url=${URL:-"${REQUEST_SCHEME:-http${HTTPS:+s}}://$HTTP_HOST$REQUEST_URI"}
yuuji@0: urlbase=${url%%\?*}
yuuji@117: msgdir=$templ/msg
yuuji@0: timeout="+2 days"
yuuji@117: memoplimitdays="7"
yuuji@252: dumpcollen=22
yuuji@67: #thumbxy=120x120
yuuji@0: thumbxy=96x96
yuuji@322: iconxy_S=80x80
yuuji@322: iconxy_M=400x400
yuuji@0: maximagexy=1600x1600
yuuji@0: ### maximagexy=400x400
yuuji@209: file_accept='accept="image/*,text/*,audio/*,application/vnd.oasis.*,application/pdf,application/x-*"'
yuuji@236: blogreadflagrowid=0
yuuji@471: blogcutoffflagrowid=-1
yuuji@358: querylog=$tmpdir/query.log
yuuji@207:
yuuji@0: tconfs=""
yuuji@231: imgcached=cache/img.`date +%Y/%m`
yuuji@4: conftbl=_tblconf
yuuji@0: nl="
yuuji@0: "
yuuji@322: iconcachekey="profimgcache_S"
yuuji@352: case "$HTTP_USER_AGENT" in
yuuji@352: *i[Pp]hone*|*[Aa]ndroid*) touchpanel=1 ;;
yuuji@352: *) touchpanel="" ;;
yuuji@352: esac
yuuji@17: . ./s4-cgi.sh
yuuji@0:
yuuji@0: : < "hoge", "owner" => "yuuji", "date" => "2015-04-27",
yuuji@0: "text" => "hogehoge ..",
yuuji@0: "reply" => [ {"serial" => 1,
yuuji@0: "author" => "taro",
yuuji@0: "date" => "2015-04-28",
yuuji@0: "parent" => "/",
yuuji@0: "path" => "/1",
yuuji@0: "text" => "blah, blah, ....",
yuuji@0: "image" => ["a.jpg", "b.jpg"] },
yuuji@0: {"serial" => 2,
yuuji@0: "author" => "hanako",
yuuji@0: "date" => "2015-04-29",
yuuji@0: "parent" => "/",
yuuji@0: "path" => "/2",
yuuji@0: "text" => "blah, blah, ....",
yuuji@0: "image" => [] }]},
yuuji@0: {"title" => "buha", ...} ]
yuuji@0:
yuuji@0:
yuuji@0: user:=
yuuji@0: ユーザ名(英数字):name:p:text:length="20" maxlength="40"
yuuji@0: パスワード:pswd:s:password:length="20" maxlength="40"
yuuji@0: 説明(日本語OK):gecos:s:text:length="20" maxlength="40"
yuuji@0: セッションキー:skey:s:session
yuuji@0: メイルアドレス:email:m:text:length="20" maxlength="40"
yuuji@0: 住所:address:m:textarea:maxlength="400"
yuuji@0: プロフィール画像:profimg:m:image:maxlength="400K"
yuuji@0: 履歴書:profpdf:m:document:maxlength="4M"
yuuji@0:
yuuji@0: 変換表
yuuji@0: /user/email=m
yuuji@0:
yuuji@0: blog:=
yuuji@0: シリアル:id:p:serial
yuuji@0: タイトル:title:s:text:
yuuji@0: 所有者:owner:s:owner:
yuuji@0: 時刻:ctime:s:stamp:
yuuji@0: リード文:heading:s:textarea:
yuuji@0: リプライ:reply:m:*article:
yuuji@0:
yuuji@0: article:=
yuuji@0: シリアル:id:p:serial
yuuji@0: 筆者:author:s:owner
yuuji@0: 時刻:ctime:s:stamp:
yuuji@0: 参照元:parent:s:parent:
yuuji@0: パス:path:s:path:
yuuji@0: 本文:text:s:textarea:
yuuji@0: 画像:image:m:image:
yuuji@0:
yuuji@0: 履歴書:profpdf:m:document:maxlength="4M"
yuuji@0:
yuuji@0:
yuuji@0: EOF
yuuji@0:
yuuji@0: sq() {
yuuji@0: # ./args.rb -cmd ".timeout 3000" "$@"
yuuji@0: sqlite3 -cmd 'PRAGMA foreign_keys=ON' -cmd ".timeout 3000" "$@"
yuuji@0: }
yuuji@163: dbsetup() {
yuuji@163: [ -d $tmpdir ] || mkdir -m 1777 $tmpdir
yuuji@163: [ -d $dbdir ] || mkdir -m 1775 $dbdir
yuuji@163: sqi=$tmpdir/sqi.$$
yuuji@163: sqo=$tmpdir/sqo.$$
yuuji@163: mkfifo $sqi $sqo
yuuji@163: #tail -f $sqi | sq $db & # "tail -f" is too heavy. DO NOT USE!!
yuuji@163: sq $db < $sqi &
yuuji@163: sq3pid="`jobs -p` $!"
yuuji@163: exec 2>> $tmpdir/error.out
yuuji@163: exec 3>> $tmpdir/debug.out
yuuji@163: exec 5> $sqi # Turning $sqi access through fd5 for continuous open state
yuuji@163: rm $sqi
yuuji@163: }
yuuji@396: cleanup2() { # Dirty workaround for produced zombie processes
yuuji@396: pkill -9 -u `id -u` -P 1
yuuji@396: }
yuuji@163: cleanup() {
yuuji@337: trap '' INT HUP EXIT TERM PIPE
yuuji@163: echo .quit >&5
yuuji@163: kill $sq3pid
yuuji@163: kill $sq3pid
yuuji@163: rm -f $sqo $sqi
yuuji@163: rm -rf $tmpfiles
yuuji@396: cleanup2
yuuji@118: }
yuuji@358: # We want to use piped function to put querylog, but we use
yuuji@358: # simple redirection for the sake of speed.
yuuji@0: query() {
yuuji@180: echo ".once $sqo" >&5
yuuji@359: echo "`date '+%F %T'`:[${user:-NULL}] <<<" >> $querylog
yuuji@180: if [ -z "$1" ]; then
yuuji@358: tee -a $querylog
yuuji@180: else
yuuji@358: echo "$@" >> $querylog
yuuji@180: echo "$@"
yuuji@358: fi >&5
yuuji@0: cat $sqo
yuuji@358: echo '>>>' >> $querylog
yuuji@0: }
yuuji@187: _m4() {
yuuji@187: #_S4NAME_=f,f,f
yuuji@187: m4 ${_S4NAME_:+"-D_S4NAME_=${_S4NAME_}"} "$@"
yuuji@187: }
yuuji@0: ismember() {
yuuji@0: # $1=user, $2=group
yuuji@16: err ismem: "select user from grp_mem where gname=$(sqlquote $2) and user='$1';"
yuuji@431: test -n "`query \"select user from grp_mem where gname=$(sqlquote \"$2\") and user='$1';\"`"
yuuji@0: }
yuuji@0: isuser() { # Check if $1 is a valid user
yuuji@0: test -n "`query \"select name from user where name='$1';\"`"
yuuji@0: }
yuuji@0: isgroup() { # Check if $1 is a valid group
yuuji@16: err isgroup: "select gname from grp where gname=$(sqlquote $1);"
yuuji@431: test -n "`query \"select gname from grp where gname=$(sqlquote \"$1\");\"`"
yuuji@0: }
yuuji@16: isgrpowner() (
yuuji@0: # $1=user, $2=group
yuuji@16: gn=`sqlquote "$2"`
yuuji@16: sql="select user from grp_adm where gname=$gn and user='$1';"
yuuji@16: err isgrpowner: $sql
yuuji@16: test -n "`query $sql`"
yuuji@16: )
yuuji@117: getgroupadminmails() {
yuuji@117: # $1=group
yuuji@117: for i in $(getgroupadmins $1); do
yuuji@117: email4group "$1" "$i" ;
yuuji@117: done
yuuji@117: }
yuuji@56: getgroupadmins() { # $1=group
yuuji@56: # This function is called in a backquote, so needn't to be subshellized
yuuji@56: qgrp=`sqlquote "$1"`
yuuji@56: query "select user from grp_adm where gname=$qgrp;"
yuuji@56: }
yuuji@117: getgroupattr() { # $1=group $2=attr
yuuji@117: # This function is called in a backquote, so needn't to be subshellized
yuuji@117: getvalbyid grp $2 \
yuuji@431: $(query "select rowid from grp where gname=`sqlquote \"$1\"`;")
yuuji@117: }
yuuji@56: getgroupbyid() {
yuuji@16: # $1=id|gname
yuuji@431: sql="select coalesce((select gname from grp where gname=$(sqlquote \"$1\")),
yuuji@16: (select gname from grp where rowid=$(sqlquote $1)));"
yuuji@71: # err ggbyid: `echo $sql`
yuuji@16: query $sql
yuuji@56: }
yuuji@0: isfilereadable() { # $1=user $2=tbl $3=rowid
yuuji@0: # Return true if user($1) can read attachment files in tbl($2):rowid($3)
yuuji@0: [ -z "$1" -o -z "$2" -o -z "$3" ] && return 1 # invalid argument
yuuji@78:
yuuji@78: # Return true when anonymous mode
yuuji@78: [ "$anonymousmode" ] && return 0
yuuji@0: # case `getvalbyid blog mode $2` in
yuuji@0: # normal|*open*|"") return 0 ;;
yuuji@0: # *closed*)
yuuji@0: # owner=`getvalbyid blog owner $2`
yuuji@0: # if isgrp $owner; then
yuuji@0: # isgrpowner $1 $owner && return 0 || return 1
yuuji@0: # elif isuser $owner; then
yuuji@0: # [ x"$1" = x"$owner" ] && return 0 || return 1
yuuji@0: # fi
yuuji@0: # esac
yuuji@0: # ↑ 要はこういう処理を↓で一気にやっている
yuuji@0: sql="with getblog as (\
yuuji@0: select key,val from blog_s where id=(\
yuuji@0: select blogid from article where id in\
yuuji@0: (select id from $2 where rowid=$3))),\
yuuji@0: getowner as (select val from getblog where key='owner'),\
yuuji@0: getmode as (select val from getblog where key='mode')\
yuuji@0: select case\
yuuji@0: when (select author from article where\
yuuji@0: id=(select id from $2 where rowid=$3))='$1' \
yuuji@0: then 'author'\
yuuji@0: when (select val from getmode) in ('report-open', 'normal')\
yuuji@0: then 'open'\
yuuji@0: when (select val from getmode) is null \
yuuji@0: then 'open'
yuuji@0: when (select val from getowner) in (select gname from grp)\
yuuji@0: then (select user from grp_adm where \
yuuji@0: gname=(select val from getowner) and \
yuuji@0: user='$1')\
yuuji@39: when (select author from article where\
yuuji@39: id=(select id from $2 where rowid=$3))='$1'
yuuji@39: then 'user+author'
yuuji@39: else '' end;"
yuuji@356: ## err isfilereadable: sql="`echo $sql`"
yuuji@0: # caseのネストで内側のcaseがスカラーtrueを返しても外側はtrue扱いにならない
yuuji@0: result=`query "$sql"`
yuuji@0: [ -n "$result" ] && return 0
yuuji@0: return 2
yuuji@0: }
yuuji@0: linkhome() {
yuuji@0: # $1=UserOrGroup
yuuji@0: echo -n '`gecos $1`"
yuuji@0: }
yuuji@208: hreflink() {
yuuji@284: # s4 specific notation:
yuuji@284: # ^href=URL
yuuji@284: # ^iframe=URL
yuuji@284: # OSM umap Wikistyle Notation:
yuuji@284: # [[URL]] - Simle Link
yuuji@284: # [[URL|Word]] - Link with anchor word
yuuji@284: # {{URL}} -
yuuji@284: # {{URL|width}} -
yuuji@284: # {{{URL}} } -
yuuji@284: # {{{URL|height}} -
yuuji@267: _hrefptn="[-A-Za-z0-9,.:;/~_%#&+?=@!]*"
yuuji@451: sed -e "s|\[\[\#\([0-9][0-9]*\)\]\]|#\1|g" \
yuuji@451: -e "s|\[\[\($_hrefptn\)\|\([^]]*\)\]\]|\2|g" \
yuuji@284: -e "s|\[\[\($_hrefptn\)\]\]|\1|" \
yuuji@284: -e "s|{{{\($_hrefptn\)\|\(.*\)}}}||g" \
yuuji@284: -e "s|{{{\($_hrefptn\)}}}||g" \
yuuji@284: -e "s|{{\($_hrefptn\)\|\(.*\)}}||g" \
yuuji@284: -e "s|{{\($_hrefptn\)}}||g"\
yuuji@284: -e "s|^href=\($_hrefptn\)|\1|" \
yuuji@425: -e "s|^iframe=\($_hrefptn\)||" \
yuuji@426: -e "s,^#### *\(.*\),
\1
," \
yuuji@426: -e "s,^### *\(.*\),
\1
," \
yuuji@426: -e "s,^## *\(.*\),
\1
,"
yuuji@208: }
yuuji@291: minitbl() {
yuuji@291: sed -n '
yuuji@295: /^|.*|/ {; # If the line begin with "|" and has 2 or more "|"
yuuji@291: s,|$,,; # Remove trailing "|" first
yuuji@291: s,|\* *\([^|]*\) *,
\1
,g; # "|*..." to "
...
"
yuuji@291: s,| *\([^|]*\) *,
\1
,g; # "|..." to "
...
"
yuuji@291: s,^,
,; s,$,
,; # Enclose with "
" and "
"
yuuji@291: H; # Concat this line to HoldSpace
yuuji@291: s/.*//; # Delete PatternSpace for finalization
yuuji@291: $ b cont
yuuji@291: d; # If in final line, output the rest, else jump to next turn
yuuji@291: }
yuuji@291: :cont
yuuji@291: x; # For non-"|" lines, check HoldSpace
yuuji@291: /^./ {; # If HoldSpace has "|" table elements
yuuji@398: s|^.|
|; # Enclose whole elements like this:
yuuji@398: # . of ^. is workaround for FreeBSD sed
yuuji@291: # s|$|
|; #
..\n..
yuuji@291: p; # Print whole "table" element
yuuji@291: s/.*//; # Erase all when done.
yuuji@291: x; s|^||; x; # Preppend /table to the next line
yuuji@291: }
yuuji@291: x; # Back to the newest line
yuuji@291: p; # Print rest'
yuuji@291: }
yuuji@179: acclog() (
yuuji@0: # $1=table, $2=rowid
yuuji@471: n=${2%%[!-0-9]*} # Remove non-digit chars from $2(should be rowid)
yuuji@179: if [ -n "$n" ]; then
yuuji@0: now=`date +"%F %T"`
yuuji@179: #query "replace into acclog values('$user', '$1', '$n', '$now');"
yuuji@278: #query "replace into acclog values('$user', '$1', $n, '$now');"
yuuji@278: query "replace into tblaccesses values('$user', '$1', $n, '$now');"
yuuji@0: fi
yuuji@179: )
yuuji@0: gecos() (
yuuji@431: u=`sqlquote "${1:-$user}"`
yuuji@173: query "select gecos from gecoses where name=$u;"
yuuji@0: )
yuuji@16: setpar() {
yuuji@16: query "replace into par values('$session', '$1', '$2', \"$3\");"
yuuji@16: }
yuuji@16: replpar() {
yuuji@16: query "update par set val=\"$3\" where sessid='$session' and var='$1' and type='$2';"
yuuji@16: }
yuuji@0: getpar() {
yuuji@0: val=`query "select val from par where var='$1' and sessid='$session' $2;"`
yuuji@356: ## err getpar/val1: "val=[$val]"
yuuji@0: if [ -z "$val" ]; then
yuuji@0: val=`query "select val from cookie where var='$1' and sessid='$session' $2;"`
yuuji@0: fi
yuuji@356: ## err getpar/val2: "val=[$val]"
yuuji@0: case "$var" in
yuuji@0: owner)
yuuji@0: if [ x"$user" = x"$val" ]; then
yuuji@0: echo $user; return
yuuji@0: elif ismember $user $val; then
yuuji@0: echo $val; return
yuuji@0: fi ;;
yuuji@0: esac
yuuji@356: ## err getpar/ret: "val=[$val]"
yuuji@0: echo "$val"
yuuji@0: }
yuuji@0:
yuuji@0: getpartype() {
yuuji@0: query "select type from par where var='$1' and sessid='$session' $2;"
yuuji@0: }
yuuji@0: getparcount() {
yuuji@0: query "select count(*) from par where var='$1' and sessid='$session' $2;"
yuuji@0: }
yuuji@0: getparfilename() {
yuuji@0: # null if type of $1 is not file
yuuji@0: (f=`query "select val from par where var='$1' and sessid='$session' and type='file' $2;"`
yuuji@13: [ -n "$f" ] && echo $f)
yuuji@0: }
yuuji@0: sqlquote() {
yuuji@0: (v="$1"
yuuji@0: case "$v" in
yuuji@0: "") return ;; # null
yuuji@0: "X'"*) # quoted hex string
yuuji@0: echo $1 ;;
yuuji@0: *\"*) # string including dbl-quote"
yuuji@0: v=`echo "$v"|sed -e 's/\"/\"\"/g'`
yuuji@0: echo "\"$v\""
yuuji@0: return ;;
yuuji@0: *.*.*|*-*-*|*[Ee]*[Ee]*|[Ee]*|*[\ -,:-df-~]*) # string
yuuji@0: echo "\"$v\""
yuuji@0: return ;;
yuuji@0: *)
yuuji@0: if expr "$v" : '[-0-9.Ee][-0-9.Ee]*$' >/dev/null 2>&1; then
yuuji@0: echo $v # MAYBE numeric, maybe...
yuuji@0: else
yuuji@0: echo "\"$v\""
yuuji@0: fi ;;
yuuji@0: esac)
yuuji@0: }
yuuji@298: sqlquotestr() (
yuuji@298: case "$1" in
yuuji@298: *\'*) v=`echo "$1"| sed "s/'/''/g"`
yuuji@298: echo "'$v'" ;;
yuuji@298: *) echo "'$1'" ;;
yuuji@298: esac
yuuji@298: )
yuuji@0: mktempd() {
yuuji@11: TMPDIR=$tmpd mktemp -d -t $session
yuuji@0: }
yuuji@69: getcachedir() { # $1=maintable
yuuji@69: if [ -n "$imgcached" ]; then
yuuji@231: echo $imgcached/$(echo ${1:-hoge}|md5)/$thumbxy
yuuji@69: else
yuuji@69: echo $tmpd/$thumbxy
yuuji@69: fi
yuuji@69: }
yuuji@0: getval() {
yuuji@0: # $1=table $2=col $3(optional)=condition
yuuji@0: case `gettbl_coltype "/$1/$2"` in
yuuji@0: user|author) # author added 2015-06-18 for article(author)
yuuji@0: echo "$user" ;;
yuuji@0: stamp|datetime)
yuuji@0: date "+%F %T" ;;
yuuji@0: serial)
yuuji@218: (s=`getpar $2`
yuuji@0: if [ -n "$s" ]; then echo $s; else echo "`date +%s`x$$"; fi) ;;
yuuji@0: *)
yuuji@0: getpar "$2" "$3";;
yuuji@0: esac
yuuji@0: }
yuuji@0:
yuuji@0: getvalquote() {
yuuji@0: # $1=table $2=col $3(optional)=condition
yuuji@0: (v=`getval "$@"`
yuuji@0: case "$v" in
yuuji@0: "") echo NULL ;;
yuuji@0: *) sqlquote "$v" ;;
yuuji@0: esac)
yuuji@0: }
yuuji@0: getparquote() {
yuuji@431: sqlquote "`getpar $1`"
yuuji@0: }
yuuji@78: getbinbyid() {
yuuji@78: # $1=tbl $2=col $3=rowid $4=tmpdirForBinary
yuuji@78:
yuuji@78: }
yuuji@0: getvalbyid() {
yuuji@0: # $1=tbl $2=col $3=rowid $4=tmpdirForBinary
yuuji@0: # If two or more values found, save them to $tmpd/${column}.$N and
yuuji@0: # store the number of files into $tmpd/${column}.count and
yuuji@0: # their each rowid stored into $tmpd/${column}.$N.rowid.
yuuji@81: ## err gtb-$1=`gettblcols $1`, tbl=$1, col=$2, '$3'=$3
yuuji@81:
yuuji@0: (for c in `gettblcols $1`; do
yuuji@0: if [ x"$2" = x"$c" ]; then
yuuji@0: ###sq $db "select $2 from $1 where rowid=$3"
yuuji@0: query "select $2 from $1 where rowid=$3;"
yuuji@0: return
yuuji@0: fi
yuuji@0: done
yuuji@231: rowid=$3
yuuji@0: pk=`gettblpkey $1`
yuuji@0: key=`query "select $pk from $1 where rowid=$3;"`
yuuji@33: getkey="(select $pk from $1 where rowid=$3)"
yuuji@388: td=${4:-$tmpd}
yuuji@388: [ -d $td ] || mkdir -p $td
yuuji@0: ### err "select $pk from $1 where rowid=$3" - key=$key '$4(tmp)'=$4
yuuji@0: for kt in s m; do
yuuji@0: t=${1}_$kt
yuuji@0: for c in `gettbl_${kt}_cols $1`; do
yuuji@0: vcount=1 # count(val)
yuuji@0: if [ x"$2" = x"$c" ]; then
yuuji@33: #### cond="$t where $pk=\"$key\" and key=\"$c\"" #2015-07-22
yuuji@33: cond="$t where $pk=$getkey and key=\"$c\""
yuuji@3: val=`query "select val from $cond limit 1;"`
yuuji@3: type=`query "select type from $cond limit 1;"`
yuuji@0: if [ $kt = m ]; then
yuuji@0: ###vcount=`sq $db "select count(val) from $cond"`
yuuji@0: # Reset val to store filenames if type is string
yuuji@0: val=`query "select val from $cond and type like 'file:%' order by rowid;"`
yuuji@59: err gvb1-sql: "select count(val) from $cond;"
yuuji@0: vcount=`query "select count(val) from $cond;"`
yuuji@0: echo $vcount > $td/$c.count
yuuji@0: i=0
yuuji@326: ## err gvbid: i=$i vcount=$vcount
yuuji@0: while [ $i -lt $vcount ]; do
yuuji@0: slice="order by rowid limit 1 offset $i"
yuuji@0: i=$((i+1))
yuuji@0: fn=$c.$i
yuuji@113: err td=$td, fn=$fn, type=$type, val="[$val]"
yuuji@0: case $type in
yuuji@0: file:*)
yuuji@0: #file=$td/$val
yuuji@326: r_f=`query "select rowid||'//'||val from $cond $slice;"`
yuuji@326: f_rid=${r_f%%//*}
yuuji@326: file=$td/${r_f##*//}
yuuji@47: # FOR SPEED: Skip file generation if imgcache exists
yuuji@326: [ -s "$file" -a -s "$td/$fn.rowid" -a -s "$file.rowid" ] \
yuuji@326: && [ x"$f_rid" = x"`cat $td/$fn.rowid`" ] \
yuuji@326: && continue
yuuji@78: # err gvbid-get="select quote(bin) from $cond $slice;"
yuuji@326: ## err output: "fn=[$fn] file=[$file]"
yuuji@326: sq $db< "$file"
yuuji@326: .output '$td/$fn.rowid'
yuuji@0: select rowid from $cond $slice;
yuuji@326: .output '$td/$fn'
yuuji@0: select val from $cond $slice;
yuuji@326: .output '$td/${fn}.content-type'
yuuji@0: select substr(type, 6) from $cond $slice;
yuuji@0: .output stdout
yuuji@0: select quote(bin) from $cond $slice;
yuuji@0: EOF
yuuji@131: ## err gvbid-get2: "`ls -lF $file`"
yuuji@3: ## err i=$i - file=$file rowid=`cat $td/$fn.rowid`
yuuji@326: cp "$td/$fn.rowid" "$file.rowid" 2>&3 # for convenience
yuuji@326: cp "$file" "$file.orig" 2>&3
yuuji@326: ls -lh "$file" |
yuuji@326: awk '{print $5"B"}'|sed 's/BB/B/' > "$file.size"
yuuji@326: case "$type" in
yuuji@326: *:[Ii]mage*) mogrify -geometry $thumbxy "$file" ;;
yuuji@0: ### ここのアイコンを増やしたい
yuuji@0: *|*:[Aa]pplication*)
yuuji@0: convert -geometry $thumbxy $imgdir/file-icon.png \
yuuji@326: png:- > "$file"
yuuji@0: ;;
yuuji@0: esac
yuuji@0: ;;
yuuji@0: *)
yuuji@0: sq $db< "$file"
yuuji@326: ##@@## -- echo ${type#file:} > "$file.content-type"
yuuji@0: case $type in
yuuji@326: *:[Ii]mage*) mogrify -geometry $thumbxy "$file" ;;
yuuji@0: *:[Aa]pplication*)
yuuji@0: convert -geometry $thumbxy $imgdir/file-icon.png \
yuuji@0: png:- > $file ;;
yuuji@0: esac
yuuji@0: fi
yuuji@0: done
yuuji@0: ;;
yuuji@0: esac
yuuji@0: fi
yuuji@0: echo "$val" # Keep newlines by ""
yuuji@0: return
yuuji@0: fi
yuuji@0: done
yuuji@0: done)
yuuji@0: }
yuuji@0: getvalbypkey() (
yuuji@0: # $1=tbl $2=col $3=pkey $4=tmpdirForBinary
yuuji@0: pk=`gettblpkey $1`
yuuji@0: rowid=`query "select rowid from $1 where $pk='$3';"`
yuuji@0: getvalbyid "$1" "$2" $rowid $4
yuuji@0: )
yuuji@0: getvalbycond() {
yuuji@0: # $1=tbl $2=col $3=SQL-Condition
yuuji@0: ###rowid=`sq $db "select rowid from $1 where $3"`
yuuji@0: rowid=`query "select rowid from $1 where $3;"`
yuuji@0: if [ -n "$rowid" ]; then
yuuji@0: getvalbyid "$1" "$2" $rowid "$4"
yuuji@0: fi
yuuji@0: }
yuuji@0: getpwfield() {
yuuji@0: # getpwfield user column
yuuji@0: # val=`sqlite3 $db "select $2 from passwd where name='$1' $3"`
yuuji@0: val=`getvalbycond user $2 "name='$1'"`
yuuji@0: if [ -n "$val" ]; then
yuuji@0: echo "$val"
yuuji@0: return 0
yuuji@0: else
yuuji@0: return 1
yuuji@0: fi
yuuji@0: }
yuuji@0: encode() {
yuuji@0: if [ -z "$sha1" ]; then
yuuji@0: if type sha1 >/dev/null 2>&1; then
yuuji@0: sha1=sha1
yuuji@0: elif type sha1sum >/dev/null 2>&1; then
yuuji@0: sha1=sha1sum
yuuji@0: elif type gsha1sum >/dev/null 2>&1; then
yuuji@0: sha1=gsha1sum
yuuji@0: fi
yuuji@0: fi
yuuji@0: $sha1 "$@" | cut -d' ' -f1
yuuji@0: }
yuuji@322: enjpeg() {
yuuji@322: if [ -z "$cjpeg" ]; then
yuuji@322: if type cjpeg >/dev/null 2>&1; then
yuuji@322: cjpeg="cjpeg"
yuuji@322: else
yuuji@322: cjpeg="convert - jpeg:-"
yuuji@322: fi
yuuji@322: fi
yuuji@322: $cjpeg "$@"
yuuji@322: }
yuuji@0: mycrypt() (
yuuji@0: key=$1 salt=$2
yuuji@0: err \$2=$2
yuuji@0: case $2 in
yuuji@0: '$'*'$'*) salt=${salt#\$4\$}
yuuji@0: salt=${salt%\$*} ;;
yuuji@0: esac
yuuji@0: echo -n '$4$'"$salt"'$'
yuuji@144: echo "$salt$key" | encode || exit 1 # Abort if fail to call encode
yuuji@0: )
yuuji@0: hexize() {
yuuji@0: if [ -z "$hexize" ]; then
yuuji@0: if type xxd >/dev/null 2>&1; then
yuuji@0: hexize="xxd -p"
yuuji@0: else
yuuji@8: hexize_hd() {
yuuji@8: hexdump -ve '1/1 "%.2x"'
yuuji@8: }
yuuji@8: hexize="hexize_hd"
yuuji@0: fi
yuuji@0: fi
yuuji@326: cat "$@" | $hexize | tr -d '\n'
yuuji@0: }
yuuji@8: unhexize() {
yuuji@8: if [ -z "$unhex" ]; then
yuuji@8: if type xxd >/dev/null 2>&1; then
yuuji@8: unhex="xxd -p -r"
yuuji@8: elif type perl >/dev/null 2>&1; then
yuuji@8: cat >$tmpd/unhex.pl</\>/g"
yuuji@155: }
yuuji@0: enascii() {
yuuji@0: if [ -z "$enascii" ]; then
yuuji@0: if type kakasi >/dev/null 2>&1; then
yuuji@0: enascii="kakasi -Ha -Ka -Ja -Ea -ka"
yuuji@0: else
yuuji@0: enascii_now=`date +%FT%T`
yuuji@0: enascii_sed() {
yuuji@0: nkf -Z0Z1Z2 \
yuuji@0: | sed -e "s/^/$enascii_now/" -e "s|[^-0-9.A-z/,()_=]|x|g"
yuuji@0: }
yuuji@0: enascii="enascii_sed"
yuuji@0: fi
yuuji@0: fi
yuuji@0: cat "$@" | $enascii
yuuji@0: }
yuuji@154: size_h() {
yuuji@164: i="$1" oi=$1
yuuji@164: set -- B B KB MB GB TB
yuuji@164: while [ $((i)) -gt 9 -a -n "$1" ]; do # -gt 9 means $oi > 1024
yuuji@154: oi=$i
yuuji@154: i=$((i/1024))
yuuji@164: shift
yuuji@154: done
yuuji@154: echo ${oi}$1
yuuji@154: }
yuuji@0: gettblconf() {
yuuji@0: if [ -z "$tconfs" ]; then
yuuji@0: ## tconfs=`sq $db \
yuuji@0: tconfs=`query \
yuuji@0: "select tbl||'/'||col||'='||keytype||'/'||objtype from $conftbl;"`
yuuji@0: fi
yuuji@0: # /tb1/col1=p/text /tb1/col2=s/text /tb1/col3=m/image /tb2/col1=p/text ...
yuuji@0: }
yuuji@0: gettblkeys() {
yuuji@0: # $1=tbl
yuuji@0: gettblconf
yuuji@0: echo "$tconfs" | fgrep "/$1/" | \
yuuji@0: (type="" keys="" fks="" cols="" scols="" mcols="" hcols=""
yuuji@0: while IFS='=' read tc conf; do # tc=/tb1/col1 conf=s/text
yuuji@0: col=${tc##*/} type=${conf%%/*}
yuuji@0: case $type in
yuuji@0: *p*)
yuuji@0: cols=$cols"${cols:+:}$col"
yuuji@0: keys=$keys"${keys:+:}$col" ;;
yuuji@0: *f*) cols=$cols"${cols:+:}$col"
yuuji@0: fks=$fks"${fks:+:}$col" ;;
yuuji@0: *m*) mcols=$mcols"${mcols:+:}$col" ;;
yuuji@0: *s*) scols=$scols"${scols:+:}$col" ;;
yuuji@0: esac
yuuji@0: case $type in
yuuji@0: *h*) hcols=$hcols"${hcols:+:}$col" ;;
yuuji@0: esac
yuuji@0: done
yuuji@0: echo "_keys=$keys _fks=$fks _cols=$cols _scols=$scols _mcols=$mcols _hcols=$hcols")
yuuji@0: }
yuuji@0: gettblpkey() {
yuuji@0: # $1=tbl
yuuji@0: gettblkeys $1 | cut -d ' ' -f 1 | sed -e 's/.*=//' -e 's/:/ /g'
yuuji@0: }
yuuji@0: gettblfkey() {
yuuji@0: (x=`gettblkeys $1`
yuuji@0: x=${x#*_fks=} # cut before "_fks=" including
yuuji@0: echo ${x%% *} | tr ':' ' ')
yuuji@0: }
yuuji@0: gettblcols() {
yuuji@0: (x=`gettblkeys $1`
yuuji@0: x=${x#*_cols=} # cut before "_cols=" including
yuuji@0: echo ${x%% *} | tr ':' ' ')
yuuji@0: }
yuuji@0: gettbl_s_cols() {
yuuji@0: (x=`gettblkeys $1`
yuuji@0: x=${x#*_scols=} # cut before "_scols=" including
yuuji@0: echo ${x%% *} | tr ':' ' ')
yuuji@0: }
yuuji@0: gettbl_m_cols() {
yuuji@0: (x=`gettblkeys $1`
yuuji@0: x=${x#*_mcols=} # cut before "_mcols=" including
yuuji@0: echo ${x%% *} | tr ':' ' ')
yuuji@0: }
yuuji@0: gettbl_h_cols() {
yuuji@0: (x=`gettblkeys $1`
yuuji@0: x=${x#*_hcols=} # cut before "_hcols=" including
yuuji@0: echo ${x%% *} | tr ':' ' ')
yuuji@0: }
yuuji@0: gettbl_coltype() (
yuuji@0: gettblconf
yuuji@0: x=`echo "$tconfs"|fgrep $1=`
yuuji@0: x=${x#*=} # cut before =
yuuji@0: echo ${x#*/} # cut before p/ including
yuuji@0: )
yuuji@0: is_hidden() {
yuuji@0: # $1=Tbl $2=col
yuuji@0: gettblconf
yuuji@0: x=`echo "$tconfs"|fgrep /$1/$2=`
yuuji@0: x=${x#*=} # cut before =
yuuji@0: x=${x%%/*} # cut after /
yuuji@0: case $x in
yuuji@0: *h*) return 0 ;;
yuuji@0: *) return 1 ;;
yuuji@0: esac
yuuji@0: }
yuuji@0:
yuuji@0: dbsetbyid() {
yuuji@0: # $1=tbl $2=id $3=col $4=val/filename - &optional - $5=content-type
yuuji@0: (t0=$1 t=$1 p=$2 c=$3
yuuji@0: tsc=$t/$c val=$4
yuuji@386: quotedp=$(sqlquotestr "$p")
yuuji@0: unset primary update
yuuji@0: gettblconf
yuuji@0: #err tsc=$tsc, tconfs="$tconfs"
yuuji@0: conf=`echo "$tconfs"|fgrep "$tsc"=`
yuuji@0: #err conf=$conf
yuuji@0: case ${conf#*=} in
yuuji@0: p*) primary=1 ;;
yuuji@0: f*) update=1 ;;
yuuji@0: u*) ;;
yuuji@0: m*) t=${t}_m;;
yuuji@0: s*) t=${t}_s;;
yuuji@0: esac
yuuji@0: #err t=$t
yuuji@386: type=string fn=""
yuuji@0: case $conf in
yuuji@0: */password)
yuuji@0: type=encoded ### val=`echo $val|encode`
yuuji@0: ;;
yuuji@0: */image*|*/document*)
yuuji@326: type=`file --mime-type - < "$val" | cut -d' ' -f2`
yuuji@326: bin="X'`hexize "$val"`'"
yuuji@0: ;;
yuuji@0: esac
yuuji@0: pkey=`echo "$tconfs"|grep "${t0}/.*=p"|sed 1q`
yuuji@0: pkey=${pkey#/*/} # cut $tbl/
yuuji@0: pkey=${pkey%=p/*} # cut =p/... -> primary key
yuuji@0: if [ "$primary" ]; then
yuuji@0: nulls=`echo "$tconfs"|grep "$t/.*=[fu]/"|sed 's/^.*/, NULL/'|tr -d '\n'`
yuuji@0: ###sq $db "replace into $t values(\"$val\"$nulls)"
yuuji@0: query "replace into $t values(\"$val\"$nulls);"
yuuji@0: elif [ "$update" ]; then
yuuji@386: query "update $1 set $c=\"$val\" where $pkey=$quotedp;"
yuuji@0: else
yuuji@386: query "replace into $t values($quotedp, \"$c\", \"$type\", \"$val\", \"$bin\");"
yuuji@0: fi
yuuji@0: )
yuuji@0: }
yuuji@3: expire() (
yuuji@3: at="${1:-$timeout}"
yuuji@3: FMT="${2:-%F %T}"
yuuji@6: TZ=GMT gdate -d "$at" +"$FMT"
yuuji@3: )
yuuji@0: addsession() {
yuuji@0: # expireをセット
yuuji@0: # loginの先にどの画面に行くかの状態遷移表書式を決める
yuuji@0: expire=`expire ${2:-"+1min"}`
yuuji@309: query "replace into session values('$1', '$expire');"
yuuji@0: # Remove old session parameters
yuuji@0: now=`expire now`
yuuji@309: query "delete from session where expire < '$now';"
yuuji@0: }
yuuji@3: gencookie() (
yuuji@3: for kv; do
yuuji@3: expire="`expire '' '%a, %d-%b-%Y %H:%M:%S GMT'`"
yuuji@3: echo "Set-Cookie: $kv; expires=$expire"
yuuji@3: done
yuuji@3: )
yuuji@0: contenttype() {
yuuji@0: echo "Content-type: ${1:-text/html; charset=utf-8}"
yuuji@0: contenttype() {} # Only need to work once
yuuji@0: }
yuuji@0: putheader() {
yuuji@0:
yuuji@0: }
yuuji@0: putfooter() {
yuuji@187: _m4 -D_TITLE_="${TITLE:-$myname}" $layout/footer.m4.html
yuuji@0: }
yuuji@3: getcookie() (
yuuji@0: for kv in `echo $HTTP_COOKIE|sed 's/[;, ]/ /g'`; do
yuuji@0: k="${kv%%=*}"
yuuji@0: v="`echo ${kv#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
yuuji@3: query "replace into cookie values('$session', '$k', 'string', \"$v\");"
yuuji@0: done
yuuji@3: )
yuuji@0: genrandom() {
yuuji@0: # $1=columns (default: 10)
yuuji@468: dd if=/dev/urandom count=1 2>/dev/null|nkf -MB \
yuuji@468: | tr -d '+='|fold -w${1:-10}|sed -n 10p
yuuji@0: }
yuuji@268: genserial() {
yuuji@268: echo $((($(date +%s)-1433084400)/10))c$$
yuuji@268: }
yuuji@0: smail() {
yuuji@166: # smail rcpts subj (file)
yuuji@300: # $SMAIL_TO <- Recipient value of To: header
yuuji@300: # $MAIL_FROM <- From: header value
yuuji@300: from=`echo "${MAIL_FROM:-$admin}"|nkf -jM|tr -d '\n'`
yuuji@411: rcpt=`echo $1|tr ' ' '\n'|sort -u|tr '\n' ' '` # uniq and strip newlines
yuuji@117: subj=`echo $2|nkf -jM|tr -d '\n'`
yuuji@300: (_m4 -D_RCPT_="${SMAIL_TO:-$rcpt}" -D_SUBJ_="\`$subj'" -D_FROM_="$from" $msgdir/mail-header.m4
yuuji@0: cat $3 | nkf -jd ) | sendmail -f $admin $rcpt
yuuji@0: }
yuuji@0: setviastring() {
yuuji@0: table=$1
yuuji@0: oifs="$IFS"
yuuji@0: IFS="&"
yuuji@0: for us in $2; do
yuuji@0: k=${us%%=*}
yuuji@0: v="`echo ${us#*=}|tr '%+' '= '|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
yuuji@309: query "replace into $table values('$session', '$k', 'string', \"$v\");"
yuuji@0: #echo $k=$v
yuuji@0: done
yuuji@0: IFS="$oifs"
yuuji@0: }
yuuji@3: checkdomain() (
yuuji@3: # Check the validity of domain by referring DNS
yuuji@3: item=$1
yuuji@83: err checkdomain $1
yuuji@83: host ${item#*@} 1>&3 2>&3
yuuji@83: host ${item#*@} >/dev/null 2>&1
yuuji@3: )
yuuji@0: pwcheck() {
yuuji@0: # $1=passwd
yuuji@0: dbpswd=`getpwfield $user pswd`
yuuji@0: encpswd=`mycrypt "$1" "$dbpswd"`
yuuji@356: ## err user=$user, pswd=$1, db=$dbpswd, enc=$encpswd
yuuji@0: [ x"$dbpswd" = x"$encpswd" ]
yuuji@0: }
yuuji@0: mypwhash() {
yuuji@0: mycrypt `cat` `genrandom 5`
yuuji@0: }
yuuji@0: wasureta() {
yuuji@0: user=$1
yuuji@83: if ! checkdomain $user; then
yuuji@83: contenttype; echo
yuuji@187: _m4 -D_TITLE_='Invalid email' $layout/title-only.html
yuuji@83: echo "ユーザ名($user)には正しいメイルアドレスが必要です。" | html p
yuuji@83: putfooter
yuuji@0: exit 0
yuuji@0: fi
yuuji@0: newpswd=`genrandom` # newsalt=`genrandom 5`
yuuji@0: #encpswd=`mycrypt "$newpswd" "$newsalt"`
yuuji@0: encpswd=`echo $newpswd|mypwhash`
yuuji@0: dbsetbyid user $user pswd "$encpswd"
yuuji@100: # Avoid $user substitution with m4, because $url comes from user input.
yuuji@187: _m4 -D_PSWD_="$newpswd" -D_URL_="$url" -D_ADMIN_="$admin" \
yuuji@117: $msgdir/mail-newaccount.m4 \
yuuji@100: | sed "s/_USER_/$user/g" \
yuuji@0: | smail $user "New Account"
yuuji@0: }
yuuji@0: checkauth() {
yuuji@0: user=`getpar user`
yuuji@0: skc=`getpar skey` # from cookie
yuuji@0: [ -z "$user" ] && return 3
yuuji@0: skey="`getpwfield $user skey`"
yuuji@0: if [ -n "$skey" ]; then
yuuji@0: if [ x"$skey" = x"$skc" ]; then
yuuji@0: return 0
yuuji@0: fi
yuuji@0: fi
yuuji@0: pswd=`getpar pswd`
yuuji@298: quser=`sqlquotestr "$user"`
yuuji@298: dbuser=`query "SELECT name FROM user WHERE name=$quser;"`
yuuji@298: if [ -z "$dbuser" ]; then
yuuji@299: return 1
yuuji@298: elif [ x"$pswd" = x"wasureta" ]; then
yuuji@0: wasureta $user
yuuji@0: return 1 # wasureta error
yuuji@0: fi
yuuji@0: # dbpswd="`sq $db \"select pswd from passwd where name='$user'\"`"
yuuji@0: # putheader; echo; echo user=$user, db=$dbpswd, enc=$encpswd
yuuji@0: if pwcheck "$pswd"; then
yuuji@0: newsession=`genrandom 50`
yuuji@0: dbsetbyid user $user skey "$newsession"
yuuji@474: dbsetbyid user $user login "`date '+%F %T'`"
yuuji@0: gencookie "user=$user" "skey=$newsession"
yuuji@0: return 0
yuuji@0: fi
yuuji@0: return 2 # Password mismatch
yuuji@0: }
yuuji@0: showlogin() {
yuuji@0: args=`echo $myargs|tr ' ' '+'`
yuuji@187: _m4 -D_SYSNAME_="Welcome" -D_MYNAME_="$myname${args+?}$args" \
yuuji@0: $layout/login.m4.html
yuuji@0: exit 0
yuuji@0: }
yuuji@0: dologin() {
yuuji@0: checkauth
yuuji@0: st=$?
yuuji@0: if [ $st != 0 ]; then
yuuji@0: contenttype; echo
yuuji@187: _m4 -D_USER_="$user" -D_URL_="$url" -D_ADMIN_="$admin" \
yuuji@117: $msgdir/login-fail-$st.m4.html
yuuji@0: showlogin # and EXIT
yuuji@0: fi
yuuji@0: }
yuuji@67:
yuuji@67: # Do instant jobs here
yuuji@163: dbsetup
yuuji@187: trap cleanup INT HUP EXIT TERM PIPE
yuuji@163: # trap cleanup INT HUP
yuuji@67:
yuuji@67: err() {
yuuji@67: echo "$@" 1>&3
yuuji@67: }
yuuji@67:
yuuji@0: cgiinit() {
yuuji@0: session=`date +%F-$$`
yuuji@0: tmpf=tmp/stream
yuuji@11: tmpd=`tmpd=$tmpdir mktempd`
yuuji@0: tmpfiles=$tmpfiles" $tmpd"
yuuji@0: addsession $session
yuuji@0: getcookie
yuuji@0: case "$REQUEST_METHOD" in
yuuji@0: get|GET) s="$QUERY_STRING" ;;
yuuji@13: post|POST) ## dd count=$CONTENT_LENGTH bs=1 of=$tmpf 2>/dev/null #slow
yuuji@137: ## dd bs=$CONTENT_LENGTH count=1 of=$tmpf # NOT working
yuuji@13: # cat > $tmpf # too much?
yuuji@13: head -c $CONTENT_LENGTH > $tmpf # safe?
yuuji@13: (echo CL=$CONTENT_LENGTH; ls -lF $tmpf) 1>&3
yuuji@0: s="`cat tmp/stream`"
yuuji@0: tmpfiles=$tmpfiles"${tmpfiles+ }$tmpf"
yuuji@0: ;;
yuuji@0: esac
yuuji@0: case "$CONTENT_TYPE" in
yuuji@0: *boundary*)
yuuji@0: bndry=${CONTENT_TYPE#*boundary=}
yuuji@13: #for us in `LC_CTYPE=C ./mpsplit.rb "$bndry" $tmpd < $tmpf`
yuuji@13: for us in `LC_CTYPE=C ./mpsplit.pl "$bndry" $tmpd < $tmpf`
yuuji@0: do
yuuji@0: k=${us%%\=*}
yuuji@0: #echo u=$us
yuuji@11: #v="`echo ${us#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
yuuji@16: v="`echo ${us#*=}|unhexize|sed -e 's/\"/\"\"/g'`"
yuuji@0: # err k=$k v=$v
yuuji@0: case "$k" in
yuuji@0: *:filename)
yuuji@0: type='file'; k=${k%:filename}
yuuji@326: # DO NOT ALLOW Space and '|' in file names
yuuji@326: newv=`echo "$v"|sed 's/[ \|]/X/g'`
yuuji@326: if [ x"$v" != x"$newv" ]; then
yuuji@329: :
yuuji@326: fi
yuuji@326: # (echo k=$k v="[$v]"; ls -lF "$tmpd/$v"; file --mime-type "$tmpd/$v") 1>&3
yuuji@326: case `file --mime-type - < "$tmpd/$v"|cut -d' ' -f2` in
yuuji@132: [Ii]mage/x-xcf)
yuuji@326: bzip2 "$tmpd/$v"
yuuji@132: v=${v}.bz2
yuuji@132: ;;
yuuji@132: [Ii]mage/x-*|*/vnd.*) ;;
yuuji@0: [Ii]mage/*)
yuuji@326: mogrify -resize $maximagexy'>' "$tmpd/$v"
yuuji@0: ;;
yuuji@0: esac
yuuji@0: ;;
yuuji@0: *)
yuuji@0: type='string'
yuuji@0: ;;
yuuji@0: esac
yuuji@16: #sq $db "replace into par values('$session', '$k', '$type', \"$v\")"
yuuji@16: setpar "$k" "$type" "$v"
yuuji@0: done
yuuji@0: ;;
yuuji@0: *)
yuuji@0: setviastring par "$s"
yuuji@0: ;;
yuuji@0: esac
yuuji@0: }
yuuji@58: email4group() {
yuuji@59: # Get for-$1=group email address(es) for $2...=users
yuuji@58: qgrp=`sqlquote "$1"`; shift
yuuji@58: users=`for i; do sqlquote "$i"; done`
yuuji@58: users=`echo $users|tr ' ' ','`
yuuji@56: sql="select coalesce(s.val, g.user) from grp_mem g
yuuji@58: left join grp_mem_s s on g.gname=s.gname and g.user=s.user
yuuji@58: and s.key='email'
yuuji@58: where g.gname=$qgrp and g.user in ($users);"
yuuji@56: query "$sql"
yuuji@58: }
yuuji@59: email4groupbyuid() {
yuuji@59: # Get for-$1=group email address(es) for $2...=user-ids
yuuji@59: qgrp=`sqlquote "$1"`; shift
yuuji@59: uids=`echo "$@"`
yuuji@59: uids=`echo $uids|tr ' ' ','`
yuuji@240: sql="WITH
yuuji@240: grpemails AS (
yuuji@240: SELECT gname, user, val email
yuuji@240: FROM grp_mem NATURAL JOIN grp_mem_s
yuuji@240: WHERE key='email' AND gname=$qgrp),
yuuji@240: useremails AS (
yuuji@240: SELECT user.rowid rid, user.name, val email
yuuji@240: FROM user
yuuji@240: LEFT JOIN user_s
yuuji@240: ON user.name=user_s.name AND user_s.key='email')
yuuji@240: SELECT DISTINCT coalesce(g.email, u.name)
yuuji@240: FROM useremails u LEFT JOIN grpemails g
yuuji@240: ON u.name=g.user
yuuji@240: WHERE u.rid in ($uids);"
yuuji@356: ## err email4gByid `echo $sql`
yuuji@59: query "$sql"
yuuji@59: }
yuuji@443: collectmembersbyid() {
yuuji@443: # Collect user names of group specified by grid
yuuji@443: rid=${1%%[!0-9]*} # Cleaning
yuuji@443: query "SELECT user FROM grp_mem \
yuuji@443: WHERE gname=(SELECT gname FROM grp WHERE rowid=$rid);"
yuuji@443: }
yuuji@443: collectmembersbyid() {
yuuji@443: # Collect user names of group name
yuuji@443: qgrp=`sqlquote "$1"`
yuuji@443: query "SELECT user FROM grp_mem WHERE gname=$qgrp;"
yuuji@443: }
yuuji@443: collectgecosesbyid() {
yuuji@443: # Collect user gecoses of group
yuuji@443: rid=${1%%[!0-9]*} # Cleaning
yuuji@443: query<<-EOF
yuuji@443: SELECT gecos
yuuji@443: FROM gecoses
yuuji@443: WHERE name IN (SELECT user FROM grp_mem
yuuji@443: WHERE gname=(SELECT gname FROM grp WHERE rowid=$rid));
yuuji@443: EOF
yuuji@443: }
yuuji@47: collectemail() (
yuuji@0: # Collect email addresses for group $1
yuuji@222: # If $TEAM is set, filter by team name
yuuji@222: # If $EXCEPT is set as username(s) delimited by comma,
yuuji@222: # remove $EXCEPT from list: ....NOT IN ($EXCEPT)
yuuji@47: for e; do
yuuji@47: if isuser "$e"; then
yuuji@222: em=`query "select val from user_m where name='$e' and key='email';"`
yuuji@222: [ -n "$em" ] && echo "$em" || echo "$e"
yuuji@47: else
yuuji@56: qgrp=`sqlquote "$e"`
yuuji@222: if [ -z "$TEAM" ]; then
yuuji@222: gmem="grp_mem"
yuuji@222: else
yuuji@222: tm=`sqlquote "$TEAM"`
yuuji@222: gmem="(SELECT gname, user FROM grp_mem_m WHERE gname='$e' AND key='team' AND val=$tm)"
yuuji@222: fi
yuuji@222: ex=${EXCEPT:+"AND g.user NOT IN ($EXCEPT)"}
yuuji@62: sql="select coalesce(s.val,um.val,g.user) from
yuuji@222: $gmem g left join grp_mem_s s
yuuji@26: on g.gname=s.gname and g.user=s.user and s.key='email'
yuuji@62: left join user_m um on g.user=um.name and um.key='email'
yuuji@222: where g.gname=$qgrp $ex;"
yuuji@356: ## err CollectEmail: `echo "$sql"`
yuuji@47: query "$sql"
yuuji@47: fi
yuuji@47: done
yuuji@47: )
yuuji@0: sendinvitation() (
yuuji@0: # $1=email
yuuji@26: iss="invite-`date +%s`-$user"
yuuji@117: addsession $iss +${memoplimitdays}days # 1 week due date
yuuji@0: query "replace into par values('$iss', 'invite', 'string', \"$1\");"
yuuji@0: gecos=`gecos`
yuuji@0: name=$user"${gecos:+($gecos)}"
yuuji@0: regist="$urlbase?reg+$iss"
yuuji@187: _m4 -D_URL_="$urlbase" \
yuuji@187: -D_USER_="$name" \
yuuji@187: -D_EMAIL_="$1" \
yuuji@187: -D_REGIST_="$regist" \
yuuji@187: -D_ADMIN_="$admin" \
yuuji@187: $msgdir/mail-invite.m4 \
yuuji@0: | smail $1 "BBSへの御招待"
yuuji@0: return 0
yuuji@0: )
yuuji@0: emaildomaincheck() {
yuuji@0: case "$1" in
yuuji@0: *@*@*) echo "無効なアドレスです"; return 1 ;;
yuuji@0: *@*)
yuuji@0: local=${1%@*} domain=${1#*@}
yuuji@0: if ! host $domain >/dev/null 2>&1; then
yuuji@0: echo "ドメイン($domain)が見付かりません。"
yuuji@0: return 2
yuuji@0: fi
yuuji@0: return 0
yuuji@0: ;;
yuuji@0: *) echo "正しいメイルアドレスをいれてください"; return 3 ;;
yuuji@0: esac
yuuji@0: }
yuuji@0: invite() {
yuuji@0: email=`getpar email`
yuuji@0: case $email in
yuuji@0: *@*@*) repo="無効なアドレスです" ;;
yuuji@0: *@*)
yuuji@0: local=${email%@*} domain=${email#*@}
yuuji@0: if ! repo=`emaildomaincheck $email`; then
yuuji@0: repo="招待アドレスのエラー: $repo"
yuuji@0: elif [ -n "`query \"select * from user where name='$email';\"`" ]; then
yuuji@0: repo="$email さんは既に加入しています。"
yuuji@0: elif sendinvitation $email; then
yuuji@0: repo="アドレス($email)宛に案内を送信しました。"
yuuji@0: fi ;;
yuuji@0: "") repo="招待したい人のメイルアドレスを入力してください。" ;;
yuuji@0: *) repo="無効なアドレスです" ;;
yuuji@0: esac
yuuji@26: addr=`query "select val from par where sessid like 'invite-%-$user';"`
yuuji@26: if [ -n "$addr" ]; then
yuuji@26: susp="
招待済みで加入待ちのアドレス
$addr
"
yuuji@26: fi
yuuji@187: _m4 -D_TITLE_="招待" -D_REPORT_="\`$repo'" -D_ACTION_="?invite" \
yuuji@187: -D_BODYCLASS_="default" -D_SUSPENDED_="$susp" \
yuuji@187: $layout/html.m4.html $layout/invite.m4.html
yuuji@0: }
yuuji@0: regist() {
yuuji@0: # $1=session-id-for-invitation
yuuji@187: _m4 -D_TITLE_="Invitation" $layout/html.m4.html
yuuji@0: if [ -z "$1" ]; then
yuuji@61: echo "bye bye" | html p
yuuji@0: reutrn
yuuji@0: fi
yuuji@0: email=`session=$1 getpar invite`
yuuji@0: if [ -z "$email" ];then
yuuji@0: cat<無効な招待状チケットです。
"
yuuji@319: viewtable $formdir/user.def user $1
yuuji@319: echo "
"
yuuji@319: } > $pf
yuuji@146:
yuuji@147: sqcond="WHERE name='$uname' AND key='profimg' AND type LIKE 'file:image%'"
yuuji@146: img=`query "SELECT type FROM user_m $sqcond LIMIT 1;"`
yuuji@148: imf=$tmpd/profimg.$$; touch $imf
yuuji@146: if [ -n "$img" ]; then
yuuji@311: if true; then
yuuji@311: tbl=user_m
yuuji@322: enticond="name='$uname'"
yuuji@322: imgsrc_cache "$td/main" user_m "$enticond" M
yuuji@311: else
yuuji@311: { printf '%s' "'
yuuji@311: }
yuuji@311: fi > $imf
yuuji@146: fi
yuuji@150: nblog=`query "SELECT count(id) FROM blog_s WHERE key='owner' AND \
yuuji@150: val='$uname';"`
yuuji@81: listblog $uname > $bf
yuuji@260:
yuuji@260: hometail=$tmpd/tail.$$
yuuji@260: mkfifo $hometail
yuuji@260:
yuuji@260: #Calling listgroupbytable, originally here
yuuji@81:
yuuji@260: (
yuuji@328: # Display Most Recent Entry
yuuji@328: shortval=${dumpcollen:+"substr(val, 0, $dumpcollen)"}
yuuji@328: shortval=${shortval:-val}
yuuji@252:
yuuji@340: # The m.aid in the next line is suspicious. But works fine in SQLite3...
yuuji@328: DT_SQL="SELECT b.rowid || '#' || m.aid LINK,
yuuji@253: ctime,
yuuji@253: (SELECT $shortval FROM blog_s WHERE key='title' AND id=b.id) title,
yuuji@253: (SELECT gecos FROM gecoses
yuuji@253: WHERE name=(SELECT val FROM blog_s
yuuji@257: WHERE key='owner' AND id=b.id)) owner,
yuuji@257: (SELECT $shortval val FROM article_s WHERE id=m.aid AND key='text') text
yuuji@253: FROM blog b
yuuji@253: JOIN
yuuji@254: (SELECT distinct blogid, a.id aid, max(val) ctime
yuuji@253: FROM article a, article_s s
yuuji@328: ON a.id=s.id AND a.author='$uname' AND s.key='ctime'
yuuji@253: GROUP BY blogid ORDER BY val DESC LIMIT 50
yuuji@253: ) m
yuuji@253: ON b.id=m.blogid;"
yuuji@328: # This should be as follows
yuuji@328: : <最近の書き込み先
yuuji@260:
yuuji@194: `DT_VIEW=replyblog dumptable html blog`
yuuji@194:
yuuji@194: EOF
yuuji@328: unset DT_SQL
yuuji@328: if [ x"$user" = x"$uname" ]; then
yuuji@81: # Display NEWS
yuuji@351: # 2016-06-26
yuuji@351: if [ x"`getpar readchk``getpar read`" = x"yesyes" ]; then
yuuji@351: acclog blog $blogreadflagrowid
yuuji@351: # echo "全部既読にしました" | html p
yuuji@175: fi
yuuji@351: # 2016-02-19 Counting NEWS without using dumptable.
yuuji@351: sql=`listnewblogsql "$user"`
yuuji@471: # echo "$sql" > tmp/listnew
yuuji@351: new10=`DT_SQL="$sql" DT_VIEW=replyblog dumptable html blog`
yuuji@81: cont=`echo "$new10"|grep "^
"|wc -l`
yuuji@81: cont=$((cont-1))
yuuji@81: err newcount=$cont
yuuji@81: if [ $cont -gt 0 ]; then
yuuji@260: #echo "全体の新着記事${cont}傑" | html h2
yuuji@340: cgi_radio foldtabs yes 'id="new10" accesskey="f"'
yuuji@428: echo "
'
yuuji@0: done
yuuji@0: echo ''
yuuji@0: }
yuuji@0: iconhref() (
yuuji@0: # $1=icon-file, $2=Href $3=title $4...=anchor
yuuji@326: data=`percenthex "$1"`
yuuji@326: ct=`file --mime-type - < "$1"|cut -d' ' -f2`
yuuji@356: ## err iconhref: \$1=$1 \$2=$2 \$3="$@"
yuuji@0: href=$2; title=$3; shift 3
yuuji@0: echo "$@"
yuuji@0: )
yuuji@0: iconhref2() (
yuuji@0: # $1=icon-file, $2=Href $3=title $4...=anchor
yuuji@0: src=$1
yuuji@0: href=$2; title=$3; shift 3
yuuji@0: echo "$@"
yuuji@0: )
yuuji@0: listentry() (
yuuji@246: # $1=user/group $2=SearchKeyword $3=condition(if any) $4=grprowid(if in grp)
yuuji@0: # Referring variable $iamowner=$grp to attach owner-request links
yuuji@356: ## err listentry: \$1=$1 \$2=$2 \$3=$3
yuuji@246: cond='' hiddens=''
yuuji@447: offset=`getpar offset`; offset=${offset%%[!0-9]*}
yuuji@447: if [ -z "$offset" ]; then
yuuji@447: offset=`getpar start`; offset=${offset%%[!0-9]*}
yuuji@447: offset=$((offset-1))
yuuji@447: fi
yuuji@0: offset=$((offset + 0)) # change to numeric forcibly
yuuji@0: [ $offset -lt 0 ] && offset=0
yuuji@0: limit=30
yuuji@78: dir=`getcachedir "$1"`
yuuji@0: if [ x"$1" = x"user" ]; then
yuuji@0: hrb="$myname?home"
yuuji@0: deficon=person-default.png
yuuji@246: entity="ユーザ" tbl=user link=rowid nm=name # stage=mems
yuuji@246: [ -n "$4" ] && hiddens=`cgi_hidden grid $4`
yuuji@33: gcs=gecos
yuuji@0: else # if group
yuuji@0: hrb="$myname?grp"
yuuji@22: deficon=group-default.png
yuuji@16: entity="グループ" tbl=grp link=rowid nm=gname stage=grps
yuuji@33: gcs=name
yuuji@0: tagline=`grep :tag: $formdir/grp.def|cut -d: -f5-`
yuuji@0: if [ -n "$tagline" ]; then
yuuji@0: tagconv=`echo $tagline|sed 's/\([^= :]*\)=\([^= :]*\)/-D\2=\1/g'`
yuuji@356: ## err tagconv=$tagconv
yuuji@0: fi
yuuji@0: fi
yuuji@0: if [ ! -d $dir ]; then
yuuji@0: mkdir -p $dir
yuuji@131: fi
yuuji@131: if [ ! -s $dir/$deficon ]; then
yuuji@0: convert -geometry $thumbxy $imgdir/$deficon $dir/$deficon
yuuji@0: fi
yuuji@0: if [ -n "$2" ]; then
yuuji@0: cond="where nick like '%$2%' or b.name like '%$2%'"
yuuji@0: fi
yuuji@0:
yuuji@0: # XX: これ複雑すぎるかな。もっとシンプルにしたい。$3条件も。2015-07-08
yuuji@33: # grpは呼出し元の動的スコープ変数でよくないな...
yuuji@33: ##qgrp=`sqlquote $grp`
yuuji@33: getgrp="(select gname from grp where rowid=${rowid:--1})"
yuuji@220: sql="select a.rowid, a.$link,
yuuji@220: coalesce(b.$gcs, a.$nm) as nick,
yuuji@388: quote(a.$nm) as qname,
yuuji@388: (SELECT val FROM ${tbl}_s
yuuji@388: WHERE $nm=a.$nm AND key='$iconcachekey') icon,
yuuji@220: coalesce(b.gecos, a.$nm) /* If group, concat (Nusers) */
yuuji@220: || case when a.$nm in (select gname from grp)
yuuji@220: then printf('(%d名)',
yuuji@220: (select count(user) from grp_mem where gname=a.$nm))
yuuji@233: else ' <'||a.$nm||'>'
yuuji@220: end
yuuji@220: as name,
yuuji@33: b.tag,
yuuji@13: case when a.$nm in (select user from grp_adm
yuuji@69: where gname=$getgrp) then '(管理者)'
yuuji@13: when '$user' in (select user from grp_adm where gname=a.$nm)
yuuji@13: then '(ADMIN)'
yuuji@171: when '$user' in (select user from grp_mem where gname=a.$nm)
yuuji@171: then '(Member)'
yuuji@13: when '$iamowner' = '' then ''
yuuji@259: else ',not='||a.rowid end as ownerlink,
yuuji@259: CASE '$entity'
yuuji@259: WHEN 'グループ'
yuuji@259: THEN coalesce(
yuuji@259: (SELECT val FROM grp_s WHERE gname=a.$nm AND key='regmode'),
yuuji@259: 'open')
yuuji@259: ||
yuuji@259: CASE WHEN '$user'
yuuji@259: IN (SELECT user FROM grp_mem WHERE gname=a.$nm)
yuuji@259: THEN ' ismember'
yuuji@259: ELSE ''
yuuji@259: END
yuuji@259: ELSE 'user'
yuuji@259: END regmode
yuuji@0: from $tbl a left join
yuuji@0: (select $nm as name,
yuuji@0: max(case key when 'gecos' then val end) as gecos,
yuuji@297: max(case key when 'tag' then val end) as tag,
yuuji@387: max(case key when 'mtime' then val end) as mtime,
yuuji@387: max(case key when 'wtime' then val end) as wtime
yuuji@474: max(case key when 'login' then val end) as login
yuuji@0: from ${tbl}_s group by $nm)
yuuji@0: b on a.$nm=b.name $cond $3
yuuji@474: order by b.wtime desc, b.login desc,
yuuji@474: b.mtime desc, b.tag desc, a.rowid asc"
yuuji@297: # Give precedence to newer maintained groups (2016-09-24)
yuuji@297: # Note that mtime is stored only in grp_s.
yuuji@356: ## err LE:sql.1="$sql"
yuuji@0: total=`query "with x as ($sql) select count(*) from x;"`
yuuji@61: echo "${entity} 一覧" | html h2
yuuji@0: if [ $total -gt $limit ]; then
yuuji@0: echo '
yuuji@33: `cgi_hidden grp $rowid`
yuuji@0: EOF
yuuji@117: if [ x`getgroupattr $grp regmode` = x'moderated' -a -z "$ismem" ]; then
yuuji@117: echo "moderated (承認加入の)グループなので実際に参加できるのは
yuuji@117: グループ管理者が承認操作をした後になります。" | html p 'class="warn"'
yuuji@117: fi
yuuji@26: echo '
'
yuuji@0: echo '
話題一覧
'
yuuji@418: thelp="1ヶ月分のまとめには上部検索窓に @month と入れてください。"
yuuji@418: cat<<-EOF
yuuji@418:
yuuji@418: EOF
yuuji@60: cond="where a.id in (select id from blog_s where key='owner' and val=$qgrp) order by ctime desc"
yuuji@397: colstate="state:稼動状態:frozen=rowclass=凍結"
yuuji@0: DT_CHLD=article:blogid \
yuuji@371: DT_VIEW=replyblog dumptable html blog \
yuuji@438: "ctime title heading team notify:通知$colmd $colstate" "$cond"
yuuji@0:
yuuji@33: getgname="(select gname from grp where rowid=$rowid)"
yuuji@246: c="group by a.name having a.name in (select user from grp_mem where gname=$getgname)"
yuuji@33: cm="?commission+$rowid"
yuuji@246: thumbxy=50x50 listmember "" "$c" "$rowid" \
yuuji@153: |sed -e "s|\( \),not=\(.*\)|\1|" # 間違って押しやすい
yuuji@222: # team list
yuuji@222: hexteams=`hexteams "$grp"`
yuuji@222: if [ -n "$hexteams" ]; then
yuuji@222: echo "チーム一覧" | html h2
yuuji@222: echo '
'
yuuji@222: sq $db -html -header<<-EOF
yuuji@222: SELECT val TEAM,
yuuji@222: group_concat((SELECT gecos FROM gecoses WHERE name=user), ',')
yuuji@222: MEMBERS
yuuji@224: FROM grp_mem_m WHERE gname=$qgrp AND key='team' GROUP BY val;
yuuji@222: EOF
yuuji@222: echo '
'
yuuji@222: fi
yuuji@0: }
yuuji@288: grp_getbodyclass() {
yuuji@288: # Get css class name for document.
yuuji@288: # `moderated' for moderated groups
yuuji@288: # `ismember' for groups where user belongs
yuuji@288: # $1=GroupName (w/o quote)
yuuji@288: # $user=userNameCurrentlyLogin
yuuji@356: ## err grp_getbodyclass: 1="$1"
yuuji@288: qgrp=`sqlquote "$1"`
yuuji@288: query<<-EOF
yuuji@288: SELECT coalesce(
yuuji@288: (SELECT val FROM grp_s WHERE gname=$qgrp AND key='regmode'),
yuuji@288: 'open')
yuuji@288: ||
yuuji@288: CASE WHEN '$user'
yuuji@288: IN (SELECT user FROM grp_mem WHERE gname=$qgrp)
yuuji@288: THEN ' ismember'
yuuji@288: ELSE ''
yuuji@288: END;
yuuji@288: EOF
yuuji@288: }
yuuji@59: grpaction() { # $1=group-rowid
yuuji@79: err GRP_ACTION:IN
yuuji@79: grid=${1:-`getpar grp`}
yuuji@79: grp=`getgroupbyid "$grid"`
yuuji@79: if [ -z "$grp" ]; then
yuuji@118: echo "無効な指定です。" | html p; return
yuuji@118: fi
yuuji@433: if ! ismember $user "$grp"; then
yuuji@118: echo "加入者のみに許可された操作です。" | html p; return
yuuji@79: fi
yuuji@81: echo "グループ $grp 個別選択操作" \
yuuji@288: | _m4 -D_TITLE_="syscmd(\`cat')" \
yuuji@288: -D_BODYCLASS_="`grp_getbodyclass \"$grp\"`" \
yuuji@288: $layout/html.m4.html
yuuji@79:
yuuji@117: isowner=""
yuuji@117: isgrpowner "$user" "$grp" && isowner="yes"
yuuji@59: usel=`getpar usel`
yuuji@59: if [ -n "$usel" ]; then
yuuji@59: uids=$(echo `echo $usel`|tr ' ' ',')
yuuji@356: ## err grpaction-1: grp=$grp, `echo $sql`
yuuji@59: text=`getpar text`
yuuji@59:
yuuji@59: rm=`getpar rm` cfm=`getpar confirm`
yuuji@356: ## err rm=$rm cfm=$cfm
yuuji@59: if [ x"$rm" = x"yes" ]; then
yuuji@117: if [ "$isowner" ]; then
yuuji@59: if [ x"$rm$cfm" = x"yesyes" ]; then
yuuji@59: # Eliminate
yuuji@59: cond="where gname=(select gname from grp where rowid=$grid) and user in (select name from user where rowid in ($uids))"
yuuji@59: for tbl in grp_mem grp_mem_s grp_mem_m; do
yuuji@59: sql="delete from $tbl $cond;"
yuuji@59: # echo "sql=$sql"
yuuji@59: query "$sql"
yuuji@59: err rmGRPuser "$sql"
yuuji@59: done
yuuji@59: num=`query "select count(*) from user where rowid in ($uids);"`
yuuji@59: #err num=$num
yuuji@59: if [ 0$num -gt 0 ]; then
yuuji@59: sql="select coalesce(b.val,a.name) from user a left join \
yuuji@59: user_s b on a.name=b.name and key='gecos' where a.rowid in ($uids);"
yuuji@59: # err `echo "$sql"`
yuuji@59: html pre<@'`
yuuji@300: myuid=`query "SELECT rowid FROM user WHERE name='$user';"`
yuuji@300: fromad=`email4groupbyuid "$grp" "$myuid"`
yuuji@300: mail_from="$safegc <$fromad>"
yuuji@300: else
yuuji@300: mail_from="$admin"
yuuji@300: fi
yuuji@300: MAIL_FROM=$mail_from \
yuuji@300: smail "`email4groupbyuid "$grp" $usel` $user" \
yuuji@300: "$gecos さんからのメッセージ" <$grp]参加メンバーに対する操作" > $tf
yuuji@291: cmmsg="`cgi_radio rm commission id=\"cmadmin\"`
yuuji@153:
"
yuuji@222: # Get team list to which current user belongs into $hexteams
yuuji@222: myhexteams=$(hexteams "$grp" "$user")
yuuji@222: allhexteams=$(hexteams "$grp")
yuuji@227: if [ -n "$myhexteams" ]; then
yuuji@291: rmteammsg="`cgi_radio rm rmteam 'id=\"cmrmteam\"'`
yuuji@228: