s4

view s4-funcs.sh @ 240:3ba9493977e1

email4groupbyuid now accepts uname(email) as well as gname
author HIROSE Yuuji <yuuji@gentei.org>
date Thu, 30 Jun 2016 12:42:16 +0859
parents 19b92549b5b7
children 7dd85c224bbb
line source
1 #!/bin/sh
2 # Here's global variable table. Do not use this names.
3 # $HGid$
5 [ -f s4-config.sh ] && . ./s4-config.sh
7 myname=`basename ${SCRIPT_NAME:-$0}`
8 mydir=`dirname ${SCRIPT_FILENAME:-$0}`
9 myargs="$@"
10 PATH=/usr/local/sqlite3/bin:/usr/local/vim7/bin:/usr/iekei/ImageMagick/bin:/usr/local/ImageMagick/bin:$PATH
11 tmpdir=${TMPDIR:-tmp}
12 dbdir=${DBDIR:-db}
13 tmpfiles=""
14 db=${DB:-$dbdir/cgi.sq3}
15 admin=${ADMIN:-hostmaster@example.org}
16 templ=${TEMPL:-templ}
17 layout=${LAYOUT:-$templ/default}
18 formdir=${FORMDIR:-$templ/form}
19 imgdir=${IMGDIR:-img}
20 url=${URL:-"${REQUEST_SCHEME:-http${HTTPS:+s}}://$HTTP_HOST$REQUEST_URI"}
21 urlbase=${url%%\?*}
22 msgdir=$templ/msg
23 timeout="+2 days"
24 memoplimitdays="7"
25 dumpcollen=17
26 #thumbxy=120x120
27 thumbxy=96x96
28 maximagexy=1600x1600
29 ### maximagexy=400x400
30 file_accept='accept="image/*,text/*,audio/*,application/vnd.oasis.*,application/pdf,application/x-*"'
31 blogreadflagrowid=0
33 tconfs=""
34 imgcached=cache/img.`date +%Y/%m`
35 conftbl=_tblconf
36 nl="
37 "
38 . ./s4-cgi.sh
40 : <<EOF
42 資料配布、グループ管理・ML、ファイル交換、クリッカー、アンケート
43 レポート提出管理
44 ひとつのarticleをheadingにして新規ツリーを作成、あるといいかも。
46 8/4 ○グループに承認加入モードを追加
47 ○グループに参加していない場合は grpaction できない
48 Web
49 締切設定
51 8/2 ○s4.cgi生成系 → index.cgi生成
52 ○自分の提出物リスト
54 7/19 ○設置
55 ○一斉送信
56 ○getparfilename の tmpd の扱い
57 ○やっぱりs4にしようかな
58 7/18 ○書込著者からホームへのリンク
59 7/17 ○個人blogに「レポート提出用」がついたときの挙動
60 ○添付ファイル回収
61 ○imgcacheは別ディレクトリにしないと + .htaccess
62 7/15 ○レポート提出モードの表示を付ける
63 管理者権限での削除? → まだいいか
65 7/13 ○前回アクセス基準の新着数は欲しいなあ
66 ○レポート提出はどうしよう
67 → ○blogにモードを追加:
68 ○レポート提出モード
69 添付ファイル (誰が見たかログ)
70 クリッカーは別立てメニューにしないと(管理者がON/OFF)
71 ○添付ファイルの読み出し権(6/22から) ← モードで対処
74 7/9 ○管理者の追加
75 △グループメンバの操作 → 要不要を吟味
76 ○グループ情報編集の行先はそのグループがいい?
77 ○新規グループの作成はどこから入るか
78 △グループホームとユーザホームを揃える
80 7/8 ○グループ一覧をユーザ一覧と揃える。
82 7/6の次 ○グループのconf編集の入口
83 ○グループ検索
85 6/22の次 ○ホーム画面、○招待状、親記事追跡、○編集ボタン、削除ボタン、
88 6/7の次 ○blogを作ってみる || userconfig || _mのまとめ編集(削除)
89 6/7の次の次 ○userconfigの画面だけ作ってみる。
91 ○ 5/28の次 edittableに「削除」ボタンを足す
92 ○6/1 par2tableを triplex 対応に
93 select "yuuji@gentei.org",var,"text",NULL,val from par where var in (select col from _tblconf where tbl="/user" and keytype in ('p', 's'));
94 →とすると 一気に
96 ## form.def を考えなおそう:
97 ## userのように必須カラムを決まった位置に付ける?
98 ## 必須カラム、owner(foreign key passwd(name)), update datetime
99 ## ユーザ管理とグループ管理はデフォルトで持たせてしまえ
101 ## 縦持ちデータの入力/編集を供給する関数 single + multi
102 ## 持てるテーブル構造はシステム標準5種 + ユーザ定義2種類
103 ## 1. passwd
104 ## 2. grp
105 ## 3. grp_mem
106 ## 4. topic 記事のIDとなる
107 ## 5. topic_cont 特定IDの記事の内容物
108 ## 6. list 繰り返し登場あり
109 ## 7. hash 繰り返し登場なし
111 ## ● listの定義:
112 ## create table list(id unique, parentID, type, value);
113 ## ● hashの定義:
114 ## create table hash(parentID, type, value, primary key(parentID, type));
116 ## グループ属性: community, friend
117 ## ○ blob使えるのかな。streamで行けるのか? xxdで行けた。ありがたい。
118 ## form-defとtableは1対1対応でいいか
119 ## csv2sq3 で .csv.sq3 の Makefile
121 ## 書き込みオブジェクトとは何か?
122 ## topic : id, belongto, title, owner, mode
123 ## type := root | comment
124 ## topic_cont : id, topicid(F), ppath, contenttype, filename, content,
125 ## unique(id, filename)
126 ## type := body(single) | attachment(multi)
128 ## group := name(P), tag, gecos, owner(F), mode
129 ## tag := personal | friend | ... any string
130 ## group_member := gname(F), type, name(F), UNIQUE(gname, type, name)
131 ## type := "u" | "g"
132 ## できたー!
133 ## with recursive allmem as (select * from grp_mem where gname='bar' union all select grp_mem.* from grp_mem,allmem where allmem.name=grp_mem.gname) select * from allmem where type='u';
134
135 ↓以下に変更
136 with recursive allmem as
137 (select gname,val from grp_m where gname='foo'
138 union all select grp_m.gname,grp_m.val from
139 grp_m,allmem where allmem.val=grp_m.gname)
140 select val from allmem where val in (select name from user);
143 with recursive allmem as
144 (select gname,val from grp_m where gname='foo'
145 union all select grp_m.gname,grp_m.val from grp_m,allmem
146 where allmem.val=grp_m.gname)
147 select a.*, coalesce(b.val,a.val) from allmem a left join grp_mem_s b
148 on a.gname=b.gname and a.val=b.user and b.key='email'
149 where a.val in (select name from user);
152 ## triggerもできた。
153 ## 5/22から:グループ作成画面
154 ## 埋め込み画像 data:CONTENT-TYPE;base64,.....
156 ## 考え得るノードタイプ
157 ## 日報 - 個人所属かグループ所属か
158 ## 課題提出 - 個人所属かグループ所属か
159 ## グループ管理
160 ## 個人情報管理
161 ##
163 ## 例: group:sip - topic:1:sip:Aperture:yuuji:rw
164 ## - topic:2:sip:ISO:yuuji:rw
165 ## topic_cont 1:1:/:body:text...Aperture
166 ## 2:1:/1:body:text..Aperture
167 ## 3:1:/1:attachment:binary..Aperture
168 ## 4:1:/2:body:text..Aperture
169 ## 5:1:/2:attachment:binary..Aperture
170 ## 6:2:/:body:text..ISO
171 ## 7:2:/6:body:text..ISO
172 ## 8:2:/6:attachment:binary..
174 ## ログテーブル
175 ## time, who, action, tbl, id idなんか取れるかな
179 ■表設計
180 * 3つの表に分散管理
181 id格納表 + hash表 + list表
182 * *_s *_m
186 user, user_map, user_col
188 ■抽象エントリタイプ
189 * user
190 idとして機能 → table中の owner に自動挿入(?)
191 * group
192 権限判定に利用
193 * serial
194 自動idとして機能
195 * password
196 入力 type=passwordで入力
197 変更 oldpasswd, password×2 で確認後修正
198 * session
199 password認証後のセッションキーとして機能
200 * text
201 入力 type=text
202 * textarea
203 入力 textarea
204 * image|document
205 入力 type=fileで入力し、mime-typeを確認
206 * owner
207 入力時の $user で、外部キー制約が付く
208 * gowner
209 グループとしての所有者で、外部キー制約が付く
210 * timestamp
211 datetime()
212 * parent
213 木構造の場合の親の位置
214 * path
215 木構造の場合の自分の位置
217 格納タイプ
218 * list
219 表 parentID, key, val でUNIQUE(parentID, key, val)
220 * hash
221 表 parentID, key, val でUNIQUE(parentID, key)
223 オブジェクトタイプ
224 * entry
225 id, title, owner
226 * textpart
227 id, parentID, text
228 * binarypart
229 id, parentID, contenttype, filename, content
230 * content
231 hash(textpart), list(binarypart)
232 * topic
233 id, hash(content), list(reply)
234 * reply
235 id, parentID, content
236 * blog
237 list(entry)
238 blog = [topic, list(reply)]
241 blog = [ {"title" => "hoge", "owner" => "yuuji", "date" => "2015-04-27",
242 "text" => "hogehoge ..",
243 "reply" => [ {"serial" => 1,
244 "author" => "taro",
245 "date" => "2015-04-28",
246 "parent" => "/",
247 "path" => "/1",
248 "text" => "blah, blah, ....",
249 "image" => ["a.jpg", "b.jpg"] },
250 {"serial" => 2,
251 "author" => "hanako",
252 "date" => "2015-04-29",
253 "parent" => "/",
254 "path" => "/2",
255 "text" => "blah, blah, ....",
256 "image" => [] }]},
257 {"title" => "buha", ...} ]
260 user:=
261 ユーザ名(英数字):name:p:text:length="20" maxlength="40"
262 パスワード:pswd:s:password:length="20" maxlength="40"
263 説明(日本語OK):gecos:s:text:length="20" maxlength="40"
264 セッションキー:skey:s:session
265 メイルアドレス:email:m:text:length="20" maxlength="40"
266 住所:address:m:textarea:maxlength="400"
267 プロフィール画像:profimg:m:image:maxlength="400K"
268 履歴書:profpdf:m:document:maxlength="4M"
270 変換表
271 /user/email=m
273 blog:=
274 シリアル:id:p:serial
275 タイトル:title:s:text:
276 所有者:owner:s:owner:
277 時刻:ctime:s:stamp:
278 リード文:heading:s:textarea:
279 リプライ:reply:m:*article:
281 article:=
282 シリアル:id:p:serial
283 筆者:author:s:owner
284 時刻:ctime:s:stamp:
285 参照元:parent:s:parent:
286 パス:path:s:path:
287 本文:text:s:textarea:
288 画像:image:m:image:
290 履歴書:profpdf:m:document:maxlength="4M"
293 EOF
295 sq() {
296 # ./args.rb -cmd ".timeout 3000" "$@"
297 sqlite3 -cmd 'PRAGMA foreign_keys=ON' -cmd ".timeout 3000" "$@"
298 }
299 dbsetup() {
300 [ -d $tmpdir ] || mkdir -m 1777 $tmpdir
301 [ -d $dbdir ] || mkdir -m 1775 $dbdir
302 sqi=$tmpdir/sqi.$$
303 sqo=$tmpdir/sqo.$$
304 mkfifo $sqi $sqo
305 #tail -f $sqi | sq $db & # "tail -f" is too heavy. DO NOT USE!!
306 sq $db < $sqi &
307 sq3pid="`jobs -p` $!"
308 exec 2>> $tmpdir/error.out
309 exec 3>> $tmpdir/debug.out
310 exec 5> $sqi # Turning $sqi access through fd5 for continuous open state
311 rm $sqi
312 }
313 cleanup() {
314 echo .quit >&5
315 kill $sq3pid
316 kill $sq3pid
317 rm -f $sqo $sqi
318 rm -rf $tmpfiles
319 }
320 query() {
321 echo ".once $sqo" >&5
322 if [ -z "$1" ]; then
323 cat
324 else
325 echo "$@"
326 fi >&5
327 cat $sqo
328 }
329 _m4() {
330 #_S4NAME_=f,f,f
331 m4 ${_S4NAME_:+"-D_S4NAME_=${_S4NAME_}"} "$@"
332 }
333 ismember() {
334 # $1=user, $2=group
335 err ismem: "select user from grp_mem where gname=$(sqlquote $2) and user='$1';"
336 test -n "`query \"select user from grp_mem where gname=$(sqlquote $2) and user='$1';\"`"
337 }
338 isuser() { # Check if $1 is a valid user
339 test -n "`query \"select name from user where name='$1';\"`"
340 }
341 isgroup() { # Check if $1 is a valid group
342 err isgroup: "select gname from grp where gname=$(sqlquote $1);"
343 test -n "`query \"select gname from grp where gname=$(sqlquote $1);\"`"
344 }
345 isgrpowner() (
346 # $1=user, $2=group
347 gn=`sqlquote "$2"`
348 sql="select user from grp_adm where gname=$gn and user='$1';"
349 err isgrpowner: $sql
350 test -n "`query $sql`"
351 )
352 getgroupadminmails() {
353 # $1=group
354 for i in $(getgroupadmins $1); do
355 email4group "$1" "$i" ;
356 done
357 }
358 getgroupadmins() { # $1=group
359 # This function is called in a backquote, so needn't to be subshellized
360 qgrp=`sqlquote "$1"`
361 query "select user from grp_adm where gname=$qgrp;"
362 }
363 getgroupattr() { # $1=group $2=attr
364 # This function is called in a backquote, so needn't to be subshellized
365 getvalbyid grp $2 \
366 $(query "select rowid from grp where gname=`sqlquote $1`;")
367 }
368 getgroupbyid() {
369 # $1=id|gname
370 sql="select coalesce((select gname from grp where gname=$(sqlquote $1)),
371 (select gname from grp where rowid=$(sqlquote $1)));"
372 # err ggbyid: `echo $sql`
373 query $sql
374 }
375 isfilereadable() { # $1=user $2=tbl $3=rowid
376 # Return true if user($1) can read attachment files in tbl($2):rowid($3)
377 [ -z "$1" -o -z "$2" -o -z "$3" ] && return 1 # invalid argument
379 # Return true when anonymous mode
380 [ "$anonymousmode" ] && return 0
381 # case `getvalbyid blog mode $2` in
382 # normal|*open*|"") return 0 ;;
383 # *closed*)
384 # owner=`getvalbyid blog owner $2`
385 # if isgrp $owner; then
386 # isgrpowner $1 $owner && return 0 || return 1
387 # elif isuser $owner; then
388 # [ x"$1" = x"$owner" ] && return 0 || return 1
389 # fi
390 # esac
391 # ↑ 要はこういう処理を↓で一気にやっている
392 sql="with getblog as (\
393 select key,val from blog_s where id=(\
394 select blogid from article where id in\
395 (select id from $2 where rowid=$3))),\
396 getowner as (select val from getblog where key='owner'),\
397 getmode as (select val from getblog where key='mode')\
398 select case\
399 when (select author from article where\
400 id=(select id from $2 where rowid=$3))='$1' \
401 then 'author'\
402 when (select val from getmode) in ('report-open', 'normal')\
403 then 'open'\
404 when (select val from getmode) is null \
405 then 'open'
406 when (select val from getowner) in (select gname from grp)\
407 then (select user from grp_adm where \
408 gname=(select val from getowner) and \
409 user='$1')\
410 when (select author from article where\
411 id=(select id from $2 where rowid=$3))='$1'
412 then 'user+author'
413 else '' end;"
414 err isfilereadable: sql="`echo $sql`"
415 # caseのネストで内側のcaseがスカラーtrueを返しても外側はtrue扱いにならない
416 result=`query "$sql"`
417 [ -n "$result" ] && return 0
418 return 2
419 }
420 linkhome() {
421 # $1=UserOrGroup
422 echo -n '<a href="?'
423 if isuser $1; then
424 err "select 'home+'||rowid from user where name='$1';"
425 query "select 'home+'||rowid from user where name='$1';"
426 else
427 echo -n "grp+$1"
428 fi
429 echo "\">`gecos $1`</a>"
430 }
431 hreflink() {
432 sed -e "s|^href=\([-A-Za-z0-9,.:;/~_%#&+?=]*\)|<a &>\1</a>|"
433 }
434 acclog() (
435 # $1=table, $2=rowid
436 n=${2%%[!0-9]*} # Remove non-digit chars from $2(should be rowid)
437 if [ -n "$n" ]; then
438 now=`date +"%F %T"`
439 #query "replace into acclog values('$user', '$1', '$n', '$now');"
440 query "replace into acclog values('$user', '$1', $n, '$now');"
441 fi
442 )
443 gecos() (
444 u=`sqlquote ${1:-$user}`
445 #gecos=`query "select val from user_s where name='$u' and key='gecos';"`
446 # sql="select case when (select name from user where name=$u) is not null
447 # then coalesce(
448 # (select val from user_s where name=$u and key='gecos'),
449 # $u)
450 # when (select gname from grp where gname=$u) is not null
451 # then coalesce(
452 # (select val from grp_s where gname=$u and key='gecos'),
453 # $u)
454 # else $u
455 # end;"
456 #query "$sql"
457 query "select gecos from gecoses where name=$u;"
458 )
459 setpar() {
460 query "replace into par values('$session', '$1', '$2', \"$3\");"
461 }
462 replpar() {
463 query "update par set val=\"$3\" where sessid='$session' and var='$1' and type='$2';"
464 }
465 getpar() {
466 err getpar: "select val from par where var='$1' and sessid='$session' $2;"
467 val=`query "select val from par where var='$1' and sessid='$session' $2;"`
468 err getpar/val1: "val=[$val]"
469 if [ -z "$val" ]; then
470 val=`query "select val from cookie where var='$1' and sessid='$session' $2;"`
471 fi
472 err getpar/val2: "val=[$val]"
473 case "$var" in
474 owner)
475 if [ x"$user" = x"$val" ]; then
476 echo $user; return
477 elif ismember $user $val; then
478 echo $val; return
479 fi ;;
480 esac
481 err getpar/ret: "val=[$val]"
482 echo "$val"
483 }
485 getpartype() {
486 query "select type from par where var='$1' and sessid='$session' $2;"
487 }
488 getparcount() {
489 query "select count(*) from par where var='$1' and sessid='$session' $2;"
490 }
491 getparfilename() {
492 # null if type of $1 is not file
493 (f=`query "select val from par where var='$1' and sessid='$session' and type='file' $2;"`
494 [ -n "$f" ] && echo $f)
495 }
496 sqlquote() {
497 (v="$1"
498 case "$v" in
499 "") return ;; # null
500 "X'"*) # quoted hex string
501 echo $1 ;;
502 *\"*) # string including dbl-quote"
503 v=`echo "$v"|sed -e 's/\"/\"\"/g'`
504 echo "\"$v\""
505 return ;;
506 *.*.*|*-*-*|*[Ee]*[Ee]*|[Ee]*|*[\ -,:-df-~]*) # string
507 echo "\"$v\""
508 return ;;
509 *)
510 if expr "$v" : '[-0-9.Ee][-0-9.Ee]*$' >/dev/null 2>&1; then
511 echo $v # MAYBE numeric, maybe...
512 else
513 echo "\"$v\""
514 fi ;;
515 esac)
516 }
517 mktempd() {
518 TMPDIR=$tmpd mktemp -d -t $session
519 }
520 getcachedir() { # $1=maintable
521 if [ -n "$imgcached" ]; then
522 echo $imgcached/$(echo ${1:-hoge}|md5)/$thumbxy
523 else
524 echo $tmpd/$thumbxy
525 fi
526 }
527 getval() {
528 # $1=table $2=col $3(optional)=condition
529 case `gettbl_coltype "/$1/$2"` in
530 user|author) # author added 2015-06-18 for article(author)
531 echo "$user" ;;
532 stamp|datetime)
533 date "+%F %T" ;;
534 serial)
535 (s=`getpar $2`
536 if [ -n "$s" ]; then echo $s; else echo "`date +%s`x$$"; fi) ;;
537 *)
538 getpar "$2" "$3";;
539 esac
540 }
542 getvalquote() {
543 # $1=table $2=col $3(optional)=condition
544 (v=`getval "$@"`
545 case "$v" in
546 "") echo NULL ;;
547 *) sqlquote "$v" ;;
548 esac)
549 }
550 getparquote() {
551 sqlquote `getpar $1`
552 }
553 getbinbyid() {
554 # $1=tbl $2=col $3=rowid $4=tmpdirForBinary
556 }
557 getvalbyid() {
558 # $1=tbl $2=col $3=rowid $4=tmpdirForBinary
559 # If two or more values found, save them to $tmpd/${column}.$N and
560 # store the number of files into $tmpd/${column}.count and
561 # their each rowid stored into $tmpd/${column}.$N.rowid.
562 ## err gtb-$1=`gettblcols $1`, tbl=$1, col=$2, '$3'=$3
564 (for c in `gettblcols $1`; do
565 if [ x"$2" = x"$c" ]; then
566 err "select $2 from $1 where rowid=$3"
567 ###sq $db "select $2 from $1 where rowid=$3"
568 query "select $2 from $1 where rowid=$3;"
569 return
570 fi
571 done
572 rowid=$3
573 pk=`gettblpkey $1`
574 key=`query "select $pk from $1 where rowid=$3;"`
575 getkey="(select $pk from $1 where rowid=$3)"
576 ### err "select $pk from $1 where rowid=$3" - key=$key '$4(tmp)'=$4
577 for kt in s m; do
578 td=${4:-$tmpd}
579 [ -d $td ] || mkdir -p $td
580 t=${1}_$kt
581 for c in `gettbl_${kt}_cols $1`; do
582 vcount=1 # count(val)
583 if [ x"$2" = x"$c" ]; then
584 #### cond="$t where $pk=\"$key\" and key=\"$c\"" #2015-07-22
585 cond="$t where $pk=$getkey and key=\"$c\""
586 val=`query "select val from $cond limit 1;"`
587 type=`query "select type from $cond limit 1;"`
588 if [ $kt = m ]; then
589 ###vcount=`sq $db "select count(val) from $cond"`
590 # Reset val to store filenames if type is string
591 val=`query "select val from $cond and type like 'file:%' order by rowid;"`
592 err gvb1-sql: "select count(val) from $cond;"
593 vcount=`query "select count(val) from $cond;"`
594 echo $vcount > $td/$c.count
595 i=0
596 err gvbid: i=$i vcount=$vcount
597 while [ $i -lt $vcount ]; do
598 slice="order by rowid limit 1 offset $i"
599 i=$((i+1))
600 fn=$c.$i
601 err td=$td, fn=$fn, type=$type, val="[$val]"
602 case $type in
603 file:*)
604 #file=$td/$val
605 file=$td/`query "select val from $cond $slice;"`
606 # FOR SPEED: Skip file generation if imgcache exists
607 [ -s $file -a -s $td/$fn.rowid -a -s $file.rowid ] && continue
608 # err gvbid-get="select quote(bin) from $cond $slice;"
609 sq $db<<EOF | unhexize > $file
610 .output $td/$fn.rowid
611 select rowid from $cond $slice;
612 .output $td/$fn
613 select val from $cond $slice;
614 .output $file.content-type
615 select substr(type, 6) from $cond $slice;
616 .output stdout
617 select quote(bin) from $cond $slice;
618 EOF
619 ## err gvbid-get2: "`ls -lF $file`"
620 ## err i=$i - file=$file rowid=`cat $td/$fn.rowid`
621 cp $td/$fn.rowid $file.rowid 2>&3 # for convenience
622 cp $file $file.orig 2>&3
623 ls -lh $file | awk '{print $5"B"}'|sed 's/BB/B/' > $file.size
624 case $type in
625 *:[Ii]mage*) mogrify -geometry $thumbxy $file ;;
626 ### ここのアイコンを増やしたい
627 *|*:[Aa]pplication*)
628 convert -geometry $thumbxy $imgdir/file-icon.png \
629 png:- > $file
630 ;;
631 esac
632 ;;
633 *)
634 sq $db<<EOF
635 .output $td/$fn.rowid
636 select rowid from $cond $slice;
637 .output $td/$fn
638 select val from $cond $slice;
639 EOF
640 val=$val${val:+$nl}"`echo $fn`" # should be delimited by newline
641 ;;
642 esac
643 done
644 else
645 rm -f $td/$c.count
646 case $type in
647 file:*)
648 echo "$val" \
649 | while read fn; do
650 file=$td/$fn
651 if [ ! -s $file ]; then
652 ## sq $db "select quote(bin) from $cond and val=\"$fn\"" \
653 query "select quote(bin) from $cond and val=\"$fn\";" \
654 | unhexize > $file
655 echo ${type#file:} > $file.content-type
656 # err TTTTTTTTTTTTTTTT: $type
657 case $type in
658 *:[Ii]mage*) mogrify -geometry $thumbxy $file ;;
659 *:[Aa]pplication*)
660 convert -geometry $thumbxy $imgdir/file-icon.png \
661 png:- > $file ;;
662 esac
663 fi
664 done
665 ;;
666 esac
667 fi
668 echo "$val" # Keep newlines by ""
669 return
670 fi
671 done
672 done)
673 }
674 getvalbypkey() (
675 # $1=tbl $2=col $3=pkey $4=tmpdirForBinary
676 pk=`gettblpkey $1`
677 rowid=`query "select rowid from $1 where $pk='$3';"`
678 getvalbyid "$1" "$2" $rowid $4
679 )
680 getvalbycond() {
681 # $1=tbl $2=col $3=SQL-Condition
682 ###rowid=`sq $db "select rowid from $1 where $3"`
683 rowid=`query "select rowid from $1 where $3;"`
684 if [ -n "$rowid" ]; then
685 getvalbyid "$1" "$2" $rowid "$4"
686 fi
687 }
688 getpwfield() {
689 # getpwfield user column
690 # val=`sqlite3 $db "select $2 from passwd where name='$1' $3"`
691 val=`getvalbycond user $2 "name='$1'"`
692 if [ -n "$val" ]; then
693 echo "$val"
694 return 0
695 else
696 return 1
697 fi
698 }
699 encode() {
700 if [ -z "$sha1" ]; then
701 if type sha1 >/dev/null 2>&1; then
702 sha1=sha1
703 elif type sha1sum >/dev/null 2>&1; then
704 sha1=sha1sum
705 elif type gsha1sum >/dev/null 2>&1; then
706 sha1=gsha1sum
707 fi
708 fi
709 $sha1 "$@" | cut -d' ' -f1
710 }
711 mycrypt() (
712 key=$1 salt=$2
713 err \$2=$2
714 case $2 in
715 '$'*'$'*) salt=${salt#\$4\$}
716 salt=${salt%\$*} ;;
717 esac
718 echo -n '$4$'"$salt"'$'
719 echo "$salt$key" | encode || exit 1 # Abort if fail to call encode
720 )
721 hexize() {
722 if [ -z "$hexize" ]; then
723 if type xxd >/dev/null 2>&1; then
724 hexize="xxd -p"
725 else
726 hexize_hd() {
727 hexdump -ve '1/1 "%.2x"'
728 }
729 hexize="hexize_hd"
730 fi
731 fi
732 cat $1 | $hexize | tr -d '\n'
733 }
734 unhexize() {
735 if [ -z "$unhex" ]; then
736 if type xxd >/dev/null 2>&1; then
737 unhex="xxd -p -r"
738 elif type perl >/dev/null 2>&1; then
739 cat >$tmpd/unhex.pl<<EOF
740 s/([0-9a-f]{2})/print chr hex \$1/gie
741 EOF
742 # Perl refuses -e in setuid circumstances, which can be absurdly
743 # avoided by creating scripts in a file where its parent directory is
744 # world writable...:)
745 unhex="perl -n $tmpd/unhex.pl"
746 fi
747 fi
748 cat $1 | $unhex
749 # cat $1 | tee /tmp/uh.in| $unhex | tee /tmp/uh.out
750 }
751 percenthex() {
752 hexize $1 | sed 's/\(..\)/%\1/g'
753 }
754 htmlescape() {
755 sed -e 's/\&/\&amp;/g' -e 's/"/\&quot;/g' -e "s/'/\&apos;/g" \
756 -e "s/</\&lt;/g; s/>/\&gt;/g"
757 }
758 enascii() {
759 if [ -z "$enascii" ]; then
760 if type kakasi >/dev/null 2>&1; then
761 enascii="kakasi -Ha -Ka -Ja -Ea -ka"
762 else
763 enascii_now=`date +%FT%T`
764 enascii_sed() {
765 nkf -Z0Z1Z2 \
766 | sed -e "s/^/$enascii_now/" -e "s|[^-0-9.A-z/,()_=]|x|g"
767 }
768 enascii="enascii_sed"
769 fi
770 fi
771 cat "$@" | $enascii
772 }
773 size_h() {
774 i="$1" oi=$1
775 set -- B B KB MB GB TB
776 while [ $((i)) -gt 9 -a -n "$1" ]; do # -gt 9 means $oi > 1024
777 oi=$i
778 i=$((i/1024))
779 shift
780 done
781 echo ${oi}$1
782 }
783 gettblconf() {
784 if [ -z "$tconfs" ]; then
785 ## tconfs=`sq $db \
786 tconfs=`query \
787 "select tbl||'/'||col||'='||keytype||'/'||objtype from $conftbl;"`
788 fi
789 # /tb1/col1=p/text /tb1/col2=s/text /tb1/col3=m/image /tb2/col1=p/text ...
790 }
791 gettblkeys() {
792 # $1=tbl
793 gettblconf
794 echo "$tconfs" | fgrep "/$1/" | \
795 (type="" keys="" fks="" cols="" scols="" mcols="" hcols=""
796 while IFS='=' read tc conf; do # tc=/tb1/col1 conf=s/text
797 col=${tc##*/} type=${conf%%/*}
798 case $type in
799 *p*)
800 cols=$cols"${cols:+:}$col"
801 keys=$keys"${keys:+:}$col" ;;
802 *f*) cols=$cols"${cols:+:}$col"
803 fks=$fks"${fks:+:}$col" ;;
804 *m*) mcols=$mcols"${mcols:+:}$col" ;;
805 *s*) scols=$scols"${scols:+:}$col" ;;
806 esac
807 case $type in
808 *h*) hcols=$hcols"${hcols:+:}$col" ;;
809 esac
810 done
811 echo "_keys=$keys _fks=$fks _cols=$cols _scols=$scols _mcols=$mcols _hcols=$hcols")
812 }
813 gettblpkey() {
814 # $1=tbl
815 gettblkeys $1 | cut -d ' ' -f 1 | sed -e 's/.*=//' -e 's/:/ /g'
816 }
817 gettblfkey() {
818 (x=`gettblkeys $1`
819 x=${x#*_fks=} # cut before "_fks=" including
820 echo ${x%% *} | tr ':' ' ')
821 }
822 gettblcols() {
823 (x=`gettblkeys $1`
824 x=${x#*_cols=} # cut before "_cols=" including
825 echo ${x%% *} | tr ':' ' ')
826 }
827 gettbl_s_cols() {
828 (x=`gettblkeys $1`
829 x=${x#*_scols=} # cut before "_scols=" including
830 echo ${x%% *} | tr ':' ' ')
831 }
832 gettbl_m_cols() {
833 (x=`gettblkeys $1`
834 x=${x#*_mcols=} # cut before "_mcols=" including
835 echo ${x%% *} | tr ':' ' ')
836 }
837 gettbl_h_cols() {
838 (x=`gettblkeys $1`
839 x=${x#*_hcols=} # cut before "_hcols=" including
840 echo ${x%% *} | tr ':' ' ')
841 }
842 gettbl_coltype() (
843 gettblconf
844 x=`echo "$tconfs"|fgrep $1=`
845 x=${x#*=} # cut before =
846 echo ${x#*/} # cut before p/ including
847 )
848 is_hidden() {
849 # $1=Tbl $2=col
850 gettblconf
851 x=`echo "$tconfs"|fgrep /$1/$2=`
852 x=${x#*=} # cut before =
853 x=${x%%/*} # cut after /
854 case $x in
855 *h*) return 0 ;;
856 *) return 1 ;;
857 esac
858 }
860 dbsetbyid() {
861 # $1=tbl $2=id $3=col $4=val/filename - &optional - $5=content-type
862 (t0=$1 t=$1 p=$2 c=$3
863 tsc=$t/$c val=$4
864 unset primary update
865 gettblconf
866 #err tsc=$tsc, tconfs="$tconfs"
867 conf=`echo "$tconfs"|fgrep "$tsc"=`
868 #err conf=$conf
869 case ${conf#*=} in
870 p*) primary=1 ;;
871 f*) update=1 ;;
872 u*) ;;
873 m*) t=${t}_m;;
874 s*) t=${t}_s;;
875 esac
876 #err t=$t
877 type=text fn=""
878 case $conf in
879 */password)
880 type=encoded ### val=`echo $val|encode`
881 ;;
882 */image*|*/document*)
883 type=`file --mime-type $val`
884 bin="X'`hexize $val`'"
885 ;;
886 esac
887 pkey=`echo "$tconfs"|grep "${t0}/.*=p"|sed 1q`
888 pkey=${pkey#/*/} # cut $tbl/
889 pkey=${pkey%=p/*} # cut =p/... -> primary key
890 if [ "$primary" ]; then
891 nulls=`echo "$tconfs"|grep "$t/.*=[fu]/"|sed 's/^.*/, NULL/'|tr -d '\n'`
892 ###sq $db "replace into $t values(\"$val\"$nulls)"
893 query "replace into $t values(\"$val\"$nulls);"
894 elif [ "$update" ]; then
895 ###sq $db "update $1 set $c=\"$val\" where $pkey=\"$p\""
896 query "update $1 set $c=\"$val\" where $pkey=\"$p\";"
897 else
898 #err "replace into $t values(\"$p\", \"$c\", \"$type\", \"$val\", \"$bin\")"
899 ###sq $db "replace into $t values(\"$p\", \"$c\", \"$type\", \"$val\", \"$bin\")"
900 query "replace into $t values(\"$p\", \"$c\", \"$type\", \"$val\", \"$bin\");"
901 fi
902 )
903 }
904 expire() (
905 at="${1:-$timeout}"
906 FMT="${2:-%F %T}"
907 TZ=GMT gdate -d "$at" +"$FMT"
908 )
909 addsession() {
910 # expireをセット
911 # loginの先にどの画面に行くかの状態遷移表書式を決める
912 expire=`expire ${2:-"+1min"}`
913 err addsession "$1" exp=$expire
914 sq $db "replace into session values('$1', '$expire')"
915 # Remove old session parameters
916 now=`expire now`
917 sq $db "delete from session where expire < '$now'"
918 }
919 gencookie() (
920 for kv; do
921 expire="`expire '' '%a, %d-%b-%Y %H:%M:%S GMT'`"
922 echo "Set-Cookie: $kv; expires=$expire"
923 done
924 )
925 contenttype() {
926 echo "Content-type: ${1:-text/html; charset=utf-8}"
927 contenttype() {} # Only need to work once
928 }
929 putheader() {
931 }
932 putfooter() {
933 _m4 -D_TITLE_="${TITLE:-$myname}" $layout/footer.m4.html
934 }
935 getcookie() (
936 for kv in `echo $HTTP_COOKIE|sed 's/[;, ]/ /g'`; do
937 k="${kv%%=*}"
938 v="`echo ${kv#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
939 query "replace into cookie values('$session', '$k', 'string', \"$v\");"
940 done
941 )
942 genrandom() {
943 # $1=columns (default: 10)
944 dd if=/dev/urandom count=1 2>/dev/null|nkf -MB|fold -w${1:-10}|sed -n 10p
945 }
946 smail() {
947 # smail rcpts subj (file)
948 # $SMAIL_TO <- Recipient value of To: header
949 rcpt=`echo $1` # strip newlines
950 subj=`echo $2|nkf -jM|tr -d '\n'`
951 (_m4 -D_RCPT_="${SMAIL_TO:-$rcpt}" -D_SUBJ_="\`$subj'" -D_FROM_=$admin $msgdir/mail-header.m4
952 cat $3 | nkf -jd ) | sendmail -f $admin $rcpt
953 }
954 setviastring() {
955 table=$1
956 oifs="$IFS"
957 IFS="&"
958 for us in $2; do
959 k=${us%%=*}
960 v="`echo ${us#*=}|tr '%+' '= '|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
961 sq $db "replace into $table values('$session', '$k', 'string', \"$v\")";
962 #echo $k=$v
963 done
964 IFS="$oifs"
965 }
966 checkdomain() (
967 # Check the validity of domain by referring DNS
968 item=$1
969 err checkdomain $1
970 host ${item#*@} 1>&3 2>&3
971 host ${item#*@} >/dev/null 2>&1
972 )
973 pwcheck() {
974 # $1=passwd
975 dbpswd=`getpwfield $user pswd`
976 encpswd=`mycrypt "$1" "$dbpswd"`
977 err user=$user, pswd=$1, db=$dbpswd, enc=$encpswd
978 [ x"$dbpswd" = x"$encpswd" ]
979 }
980 mypwhash() {
981 mycrypt `cat` `genrandom 5`
982 }
983 wasureta() {
984 user=$1
985 if ! checkdomain $user; then
986 contenttype; echo
987 _m4 -D_TITLE_='Invalid email' $layout/title-only.html
988 echo "ユーザ名($user)には正しいメイルアドレスが必要です。" | html p
989 putfooter
990 exit 0
991 fi
992 newpswd=`genrandom` # newsalt=`genrandom 5`
993 #encpswd=`mycrypt "$newpswd" "$newsalt"`
994 encpswd=`echo $newpswd|mypwhash`
995 dbsetbyid user $user pswd "$encpswd"
996 # Avoid $user substitution with m4, because $url comes from user input.
997 _m4 -D_PSWD_="$newpswd" -D_URL_="$url" -D_ADMIN_="$admin" \
998 $msgdir/mail-newaccount.m4 \
999 | sed "s/_USER_/$user/g" \
1000 | smail $user "New Account"
1002 checkauth() {
1003 user=`getpar user`
1004 skc=`getpar skey` # from cookie
1005 [ -z "$user" ] && return 3
1006 skey="`getpwfield $user skey`"
1007 err user=$user skey=$skey
1008 if [ -n "$skey" ]; then
1009 if [ x"$skey" = x"$skc" ]; then
1010 return 0
1011 fi
1012 fi
1013 pswd=`getpar pswd`
1014 if [ x"$pswd" = x"wasureta" ]; then
1015 wasureta $user
1016 return 1 # wasureta error
1017 fi
1018 # dbpswd="`sq $db \"select pswd from passwd where name='$user'\"`"
1019 # putheader; echo; echo user=$user, db=$dbpswd, enc=$encpswd
1020 if pwcheck "$pswd"; then
1021 newsession=`genrandom 50`
1022 dbsetbyid user $user skey "$newsession"
1023 gencookie "user=$user" "skey=$newsession"
1024 return 0
1025 fi
1026 return 2 # Password mismatch
1028 showlogin() {
1029 args=`echo $myargs|tr ' ' '+'`
1030 _m4 -D_SYSNAME_="Welcome" -D_MYNAME_="$myname${args+?}$args" \
1031 $layout/login.m4.html
1032 exit 0
1034 dologin() {
1035 checkauth
1036 st=$?
1037 if [ $st != 0 ]; then
1038 contenttype; echo
1039 _m4 -D_USER_="$user" -D_URL_="$url" -D_ADMIN_="$admin" \
1040 $msgdir/login-fail-$st.m4.html
1041 showlogin # and EXIT
1042 fi
1045 # Do instant jobs here
1046 dbsetup
1047 trap cleanup INT HUP EXIT TERM PIPE
1048 # trap cleanup INT HUP
1050 err() {
1051 echo "$@" 1>&3
1054 cgiinit() {
1055 session=`date +%F-$$`
1056 tmpf=tmp/stream
1057 tmpd=`tmpd=$tmpdir mktempd`
1058 tmpfiles=$tmpfiles" $tmpd"
1059 addsession $session
1060 getcookie
1061 case "$REQUEST_METHOD" in
1062 get|GET) s="$QUERY_STRING" ;;
1063 post|POST) ## dd count=$CONTENT_LENGTH bs=1 of=$tmpf 2>/dev/null #slow
1064 ## dd bs=$CONTENT_LENGTH count=1 of=$tmpf # NOT working
1065 # cat > $tmpf # too much?
1066 head -c $CONTENT_LENGTH > $tmpf # safe?
1067 (echo CL=$CONTENT_LENGTH; ls -lF $tmpf) 1>&3
1068 s="`cat tmp/stream`"
1069 tmpfiles=$tmpfiles"${tmpfiles+ }$tmpf"
1070 ;;
1071 esac
1072 case "$CONTENT_TYPE" in
1073 *boundary*)
1074 bndry=${CONTENT_TYPE#*boundary=}
1075 #for us in `LC_CTYPE=C ./mpsplit.rb "$bndry" $tmpd < $tmpf`
1076 for us in `LC_CTYPE=C ./mpsplit.pl "$bndry" $tmpd < $tmpf`
1077 do
1078 k=${us%%\=*}
1079 #echo u=$us
1080 #v="`echo ${us#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
1081 v="`echo ${us#*=}|unhexize|sed -e 's/\"/\"\"/g'`"
1082 # err k=$k v=$v
1083 case "$k" in
1084 *:filename)
1085 type='file'; k=${k%:filename}
1086 (echo k=$k; ls -lF $tmpd/$v; file --mime-type $tmpd/$v) 1>&3
1087 case `file --mime-type $tmpd/$v|cut -d' ' -f2` in
1088 [Ii]mage/x-xcf)
1089 bzip2 $tmpd/$v
1090 v=${v}.bz2
1091 ;;
1092 [Ii]mage/x-*|*/vnd.*) ;;
1093 [Ii]mage/*)
1094 mogrify -resize $maximagexy'>' $tmpd/$v
1095 ;;
1096 esac
1097 ;;
1098 *)
1099 type='string'
1100 ;;
1101 esac
1102 #sq $db "replace into par values('$session', '$k', '$type', \"$v\")"
1103 setpar "$k" "$type" "$v"
1104 done
1105 ;;
1106 *)
1107 setviastring par "$s"
1108 ;;
1109 esac
1111 email4group() {
1112 # Get for-$1=group email address(es) for $2...=users
1113 qgrp=`sqlquote "$1"`; shift
1114 users=`for i; do sqlquote "$i"; done`
1115 users=`echo $users|tr ' ' ','`
1116 sql="select coalesce(s.val, g.user) from grp_mem g
1117 left join grp_mem_s s on g.gname=s.gname and g.user=s.user
1118 and s.key='email'
1119 where g.gname=$qgrp and g.user in ($users);"
1120 err `echo $sql`
1121 query "$sql"
1123 email4groupbyuid() {
1124 # Get for-$1=group email address(es) for $2...=user-ids
1125 qgrp=`sqlquote "$1"`; shift
1126 err em4gbid-IN: "\$1=$1 qgrp=$qgrp"
1127 uids=`echo "$@"`
1128 uids=`echo $uids|tr ' ' ','`
1129 sql="WITH
1130 grpemails AS (
1131 SELECT gname, user, val email
1132 FROM grp_mem NATURAL JOIN grp_mem_s
1133 WHERE key='email' AND gname=$qgrp),
1134 useremails AS (
1135 SELECT user.rowid rid, user.name, val email
1136 FROM user
1137 LEFT JOIN user_s
1138 ON user.name=user_s.name AND user_s.key='email')
1139 SELECT DISTINCT coalesce(g.email, u.name)
1140 FROM useremails u LEFT JOIN grpemails g
1141 ON u.name=g.user
1142 WHERE u.rid in ($uids);"
1143 err email4gByid `echo $sql`
1144 query "$sql"
1146 collectemail() (
1147 # Collect email addresses for group $1
1148 # If $TEAM is set, filter by team name
1149 # If $EXCEPT is set as username(s) delimited by comma,
1150 # remove $EXCEPT from list: ....NOT IN ($EXCEPT)
1151 for e; do
1152 if isuser "$e"; then
1153 em=`query "select val from user_m where name='$e' and key='email';"`
1154 [ -n "$em" ] && echo "$em" || echo "$e"
1155 else
1156 # sql="with recursive allmem as
1157 # (select gname,val from grp_m where gname='$1'
1158 # union all select grp_m.gname,grp_m.val from grp_m,allmem
1159 # where allmem.val=grp_m.gname)
1160 # select coalesce(b.val,a.val)
1161 # from allmem a left join grp_mem_s b
1162 # on a.gname=b.gname and a.val=b.user and b.key='email'
1163 # where a.val in (select name from user) limit 10000;"
1164 # tmp tmp tmp tmp tmp tmp tmp
1165 qgrp=`sqlquote "$e"`
1166 if [ -z "$TEAM" ]; then
1167 gmem="grp_mem"
1168 else
1169 tm=`sqlquote "$TEAM"`
1170 gmem="(SELECT gname, user FROM grp_mem_m WHERE gname='$e' AND key='team' AND val=$tm)"
1171 fi
1172 ex=${EXCEPT:+"AND g.user NOT IN ($EXCEPT)"}
1173 sql="select coalesce(s.val,um.val,g.user) from
1174 $gmem g left join grp_mem_s s
1175 on g.gname=s.gname and g.user=s.user and s.key='email'
1176 left join user_m um on g.user=um.name and um.key='email'
1177 where g.gname=$qgrp $ex;"
1178 err CollectEmail: `echo "$sql"`
1179 query "$sql"
1180 fi
1181 done
1183 sendinvitation() (
1184 # $1=email
1185 iss="invite-`date +%s`-$user"
1186 addsession $iss +${memoplimitdays}days # 1 week due date
1187 query "replace into par values('$iss', 'invite', 'string', \"$1\");"
1188 gecos=`gecos`
1189 name=$user"${gecos:+($gecos)}"
1190 regist="$urlbase?reg+$iss"
1191 _m4 -D_URL_="$urlbase" \
1192 -D_USER_="$name" \
1193 -D_EMAIL_="$1" \
1194 -D_REGIST_="$regist" \
1195 -D_ADMIN_="$admin" \
1196 $msgdir/mail-invite.m4 \
1197 | smail $1 "BBSへの御招待"
1198 return 0
1200 emaildomaincheck() {
1201 case "$1" in
1202 *@*@*) echo "無効なアドレスです"; return 1 ;;
1203 *@*)
1204 local=${1%@*} domain=${1#*@}
1205 if ! host $domain >/dev/null 2>&1; then
1206 echo "ドメイン($domain)が見付かりません。"
1207 return 2
1208 fi
1209 return 0
1210 ;;
1211 *) echo "正しいメイルアドレスをいれてください"; return 3 ;;
1212 esac
1214 invite() {
1215 email=`getpar email`
1216 case $email in
1217 *@*@*) repo="無効なアドレスです" ;;
1218 *@*)
1219 local=${email%@*} domain=${email#*@}
1220 if ! repo=`emaildomaincheck $email`; then
1221 repo="招待アドレスのエラー: $repo"
1222 elif [ -n "`query \"select * from user where name='$email';\"`" ]; then
1223 repo="$email さんは既に加入しています。"
1224 elif sendinvitation $email; then
1225 repo="アドレス($email)宛に案内を送信しました。"
1226 fi ;;
1227 "") repo="招待したい人のメイルアドレスを入力してください。" ;;
1228 *) repo="無効なアドレスです" ;;
1229 esac
1230 addr=`query "select val from par where sessid like 'invite-%-$user';"`
1231 err addr=$addr
1232 if [ -n "$addr" ]; then
1233 susp="<h2>招待済みで加入待ちのアドレス</h2><pre>$addr</pre>"
1234 fi
1235 _m4 -D_TITLE_="招待" -D_REPORT_="\`$repo'" -D_ACTION_="?invite" \
1236 -D_BODYCLASS_="default" -D_SUSPENDED_="$susp" \
1237 $layout/html.m4.html $layout/invite.m4.html
1239 regist() {
1240 # $1=session-id-for-invitation
1241 _m4 -D_TITLE_="Invitation" $layout/html.m4.html
1242 if [ -z "$1" ]; then
1243 echo "bye bye" | html p
1244 reutrn
1245 fi
1246 email=`session=$1 getpar invite`
1247 if [ -z "$email" ];then
1248 cat<<EOF
1249 <p>無効な招待状チケットです。</p>
1250 <p>招待状の有効期限(1週間)が切れているか、チケット番号が異なっています。
1251 加入している人に、再度招待してもらいましょう。</p>
1252 EOF
1253 return
1254 fi
1255 echo "$email さんようこそ" | html h2
1256 query "replace into user values('$email');"
1257 # Fake login password to wasureta
1258 query "replace into par values('$session', 'pswd', 'string', 'wasureta'),
1259 ('$session', 'user', 'string', '$email');"
1260 wasureta $email
1261 echo "このアドレスに初期パスワードを送信しました。" |html p
1262 echo "新着メイルを確認してログインしてください。" |html p
1263 addsession $1 # for removal after 1 minute
1264 _m4 -D_SYSNAME_="Initial Login" -D_MYNAME_="$myname?userconf" \
1265 $layout/login.m4.html
1266 return
1268 group_safename() {
1269 # Convert $1 to safe group name
1270 echo "$1" | tr -d '"'"'",
1272 groupupdate() {
1273 gname=`getpar gname`
1274 qgname=`sqlquote $gname`
1275 err Enter:groupupdate
1276 if [ -n "$gname" ]; then
1277 # See ALSO same job in showgroup()
1278 newgname=`group_safename "$gname"`
1279 err newgname=$newgname
1280 if [ x"$newgname" != x"$gname" ]; then
1281 err NewGNAME: gname=$newgname
1282 gname=$newgname
1283 echo "使用禁止文字を除去し $gname としました。" | html p
1284 replpar gname string "$gname"
1285 fi
1286 # Name confliction check
1287 parow=`getpar rowid`
1288 err parow=$parow
1289 qgname=`sqlquote $gname` # Set again in case gname modified
1290 query "BEGIN EXCLUSIVE;"
1291 err "select count(gname) from grp where rowid != ${parow:-0} and gname = $qgname;"
1292 count=$(query "select count(gname) from grp where rowid != ${parow:-0} and gname = $qgname;")
1293 if [ $count -gt 0 ]; then
1294 echo "そのグループ名は既にあります。" | html p
1295 query "END;"
1296 return
1297 fi
1298 par2table $formdir/grp.def
1299 query "END TRANSACTION;"
1300 # Remove orphan
1301 : <<EOF
1302 select a.id,b.val from (select * from blog where id in
1303 (select id from blog_s where key='owner'
1304 and val not in (select name from user union select gname from grp)))
1305 a left join blog_s b on a.id=b.id and b.key='owner';
1306 EOF
1307 rm=`getpar rm` cfm=`getpar confirm`
1308 err groupupdate:::: after par2tbl rmcfm=$rm$cfm
1309 if [ x"$rm$cfm" = x"yesyes" ]; then
1310 if [ -z "`query \"select gname from grp where gname=$qgname;\"`" ]; then
1311 sql="delete from blog where id in
1312 (select id from blog_s where key='owner' and val=$qgname);"
1313 err rm-grp cleaning sql=`echo $sql`
1314 query "$sql";
1315 fi
1316 fi
1317 [ -z "$parow" ] && joingrp "$gname" "$user" yes "$user" as-admin
1318 fi
1319 sql="select rowid from grp where gname=$qgname;"
1320 grid=$(query $sql)
1321 err grpupdate:new-grid=$grid, sql=$sql
1322 grp $grid
1324 groupman() {
1325 note="<p>グループ名に使用できない文字は自動的に削除されます。</p>"
1327 GF_STAGE="grpconf"
1328 GF_STAGE=groupupdate
1329 DT_VIEW=grp dumptable html grp 'gname gecos:DESC mtime:TIME' 'order by b.TIME desc' \
1330 |_m4 -D_TITLE_="グループ作成" \
1331 -D_FORM_="$note`genform $formdir/grp.def`" \
1332 -D_DUMPTABLE_="syscmd(cat)" \
1333 $layout/html.m4.html $layout/form+dump.m4.html
1335 userconf() {
1336 [ -n "`getpar rowid`" ] && par2table $formdir/user.def
1337 _m4 -D_BODYCLASS_=userconf -D_TITLE_="ユーザ情報編集" $layout/html.m4.html
1338 GF_ACTION="?home" edittable "$formdir/user.def" "user" "$user"
1340 groupconf() {
1341 # $1=rowid in grp (2015-07-21 changed from gname)
1342 [ -n "`getpar rowid`" ] && par2table $formdir/grp.def
1343 _m4 -D_BODYCLASS_=groupconf -D_TITLE_="グループ情報編集" $layout/html.m4.html
1344 #rowid=`query "select rowid from grp where gname='$1';"`
1345 rowid=${1%%[!A-Z0-9a-z_]*}
1346 err gcon \$1=$1 rowid=$rowid
1347 # GF_ACTION="?grp+$1" edittable "$formdir/grp.def" "grp" "$rowid" #2015-0804
1348 GF_STAGE="groupupdate" edittable "$formdir/grp.def" "grp" "$rowid"
1350 mems() {
1351 _m4 -D_TITLE_="参加者一覧" -D_BODYCLASS_=listmember $layout/html.m4.html
1352 kwd=`getpar kwd`
1353 listmember $kwd
1355 grps() {
1356 _m4 -D_TITLE_="グループ一覧" -D_BODYCLASS_=listgroup $layout/html.m4.html
1357 kwd=`getpar kwd`
1358 listgroup $kwd \
1359 | _m4 -D_DUMPTABLE_="syscmd(cat)" \
1360 -D_TITLE_="グループ関連操作" \
1361 -D_FORM_="<a href=\"?groupman\">新規グループ作成</a>" \
1362 $layout/form+dump.m4.html
1364 grp() { # $1=group-rowid
1365 gpg=`getpar grp`
1366 grid=${1:-$gpg}
1367 grp=`getgroupbyid "$grid"`
1368 err grp: getpar-grp"(gpg)=[$grp]"
1369 ## . ./s4-blog.sh
1370 jg=`getpar joingrp`
1371 if [ -n "$jg" ]; then
1372 err jg=$jg, grp=$grp
1373 [ -n "$jg" -a -n "$grp" ] &&
1374 joingrp "$grp" "$user" "$jg" "`getpar email`"
1375 fi
1376 echo "グループ $grp"|_m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1377 showgroup "$grid"
1379 listnewblogsql() { # $1=user
1380 cat<<EOF
1381 with article_ctime as (
1382 select id,blogid,author,val ctime
1383 from article join article_s s using(id)
1384 where s.key='ctime'
1385 ), blog_title_owner as (
1386 select blog.rowid, id,
1387 max(case key when 'title' then val end) title,
1388 max(case key when 'owner' then val end) owner
1389 from blog, blog_s using(id) group by id
1390 ), acclog_user as (
1391 -- select * from acclog where user='$user' and tbl='blog'
1392 -- GET (user,tbl,tblrowid,max(time,DEFAULTtime))
1393 SELECT user, tbl, tblrowid,
1394 max(time,
1395 coalesce((SELECT time FROM acclog
1396 WHERE user='$user' and tbl='blog'
1397 AND tblrowid=$blogreadflagrowid), " ")) time
1398 FROM acclog
1399 WHERE user='$user' AND tbl='blog'
1400 ), blogall as (
1401 select b.id, b.rowid, b.owner, b.title, ctime, ac.author
1402 from blog_title_owner b, article_ctime ac
1403 on b.id=ac.blogid
1405 select rowid LINK,
1406 sum(case when l.time is not null
1407 then l.time < ctime
1408 else 1
1409 end) "新着",
1410 count(id) "総数", ctime, title,
1411 /* owner gecos */
1412 (select gecos from gecoses where name=bl.owner) gecos
1413 from blogall bl left join acclog_user l
1414 on bl.rowid=round(l.tblrowid)
1415 where case when (select name from user where owner=name) is not null
1416 then 1 /* user's diary is always readable */
1417 when (select val from grp_s
1418 where gname=owner and key='regmode') = 'moderated'
1419 and -- moderated group and nonmember can't read, not counting
1420 (select user from grp_mem
1421 where gname=owner and user='$user') is null
1422 then 0
1423 else 1
1424 end
1425 group by bl.id
1426 having "新着" > 0 order by ctime desc, "新着" desc, bl.id
1427 limit 10;
1428 EOF
1431 showhome() {
1432 # $1=userRowIdToShow
1433 err showhome \$1=$1
1434 case "$1" in
1435 *@*) uname=`getvalbypkey user name "$1"` ;;
1436 *) uname=`getvalbyid user name $1` ;;
1437 esac
1438 err ShowHome: uname=$uname
1439 gecos=`gecos "$uname"`
1440 err SH:gecos=$gecos
1441 GF_VIEWONLY=1
1442 cond="gname in (select gname from grp_mem where user='$uname')"
1443 if [ x"$user" = x"$uname" ]; then
1444 conflink="<a href=\"?userconf\">プロフィールの編集</a> /
1445 <a href=\"?blog\">新規話題の作成</a>"
1446 # Display folders
1447 sql="select count(id) from article_m where id
1448 in (select id from article where author='$user')
1449 and type like 'file:%';"
1450 err nfile-sql=`echo "$sql"`
1451 nfile=`query "$sql"`
1452 err nfile=$nfile
1453 if [ $nfile -gt 0 ]; then
1454 conflink="$conflink /
1455 <a href=\"?lsmyfile\">過去の提出ファイル</a>"
1456 fi
1457 fi
1458 . ./s4-blog.sh
1460 tf=$tmpd/title.$$ pf=$tmpd/profile.$$ bf=$tmpd/blogs.$$
1461 echo "$gecos さん" > $tf
1462 viewtable $formdir/user.def user $1 > $pf
1464 sqcond="WHERE name='$uname' AND key='profimg' AND type LIKE 'file:image%'"
1465 img=`query "SELECT type FROM user_m $sqcond LIMIT 1;"`
1466 imf=$tmpd/profimg.$$; touch $imf
1467 if [ -n "$img" ]; then
1468 { printf '%s' "<img src=\"data:${img#file:},"
1469 query "SELECT hex(bin) FROM user_m $sqcond LIMIT 1;" \
1470 | sed 's/\(..\)/%\1/g'
1471 echo '">'
1472 } > $imf
1473 fi
1474 nblog=`query "SELECT count(id) FROM blog_s WHERE key='owner' AND \
1475 val='$uname';"`
1476 listblog $uname > $bf
1477 listgroupbytable $formdir/grp.def $cond \
1478 | _m4 -D_BODYCLASS_=home -D_TITLE_="spaste(\`$tf')" \
1479 -D_PROFILE_="spaste(\`$pf')$conflink" \
1480 -D_PROFIMG_="spaste(\`$imf')" \
1481 -D_BLOGS_="spaste(\`$bf')" \
1482 -D_NBLOG_="$nblog" \
1483 -D_GROUPS_="syscmd(\`cat')" \
1484 $layout/html.m4.html $layout/home.m4.html
1486 if [ x"$user" = x"$uname" ]; then
1487 # Display Most Recent Entry
1488 shortval=${dumpcollen:+"substr(val, 0, $dumpcollen)"}
1489 shortval=${shortval:-val}
1490 DT_SQL="SELECT b.rowid LINK,
1491 ctime,
1492 (SELECT $shortval FROM blog_s WHERE key='title' AND id=b.id) title,
1493 (SELECT gecos FROM gecoses
1494 WHERE name=(SELECT val FROM blog_s
1495 WHERE key='owner' AND id=b.id)) owner
1496 FROM blog b
1497 JOIN
1498 (SELECT distinct blogid, max(val) ctime
1499 FROM article a, article_s s
1500 ON a.id=s.id AND a.author='$user' AND s.key='ctime'
1501 GROUP BY blogid ORDER BY val DESC LIMIT 50
1502 ) m
1503 ON b.id=m.blogid;"
1504 cat<<-EOF
1505 <div class="fold">
1506 `cgi_checkbox mrd yes id="mre"`<label
1507 for="mre">最近書き込んだ場所一覧</label>
1508 `DT_VIEW=replyblog dumptable html blog`
1509 </div>
1510 EOF
1511 unset DT_SQL
1512 # Display NEWS
1513 if false; then
1514 cond="where 新着 > 0 order by 新着 desc,ctime desc limit 10"
1515 new10=`DT_CHLD=article:blogid \
1516 DT_VIEW=replyblog dumptable html blog "ctime title gecos" "$cond"`
1517 else
1518 # 2016-06-26
1519 if [ x"`getpar readchk``getpar read`" = x"yesyes" ]; then
1520 acclog blog $blogreadflagrowid
1521 # echo "全部既読にしました" | html p
1522 fi
1523 # 2016-02-19 Counting NEWS without using dumptable.
1524 sql=`listnewblogsql "$user"`
1525 new10=`DT_SQL="$sql" DT_VIEW=replyblog dumptable html blog`
1526 fi
1527 cont=`echo "$new10"|grep "^<TR>"|wc -l`
1528 cont=$((cont-1))
1529 err newcount=$cont
1530 if [ $cont -gt 0 ]; then
1531 echo "全体の新着記事${cont}傑" | html h2
1532 echo "$new10"
1533 cat<<-EOF | html form 'action="?home"'
1534 <div class="fold noborder">
1535 `cgi_checkbox readchk yes 'id="read"'`<label
1536 for="read">新着ふくめて全部読んだことにする</label>
1537 <div>`cgi_submit '確定'`</div>
1538 `cgi_hidden read yes`
1539 </div>
1540 EOF
1541 fi
1542 cat<<EOF
1543 <div class="fold">
1544 `cgi_checkbox srchall yes id="sa"`<label
1545 for="sa">SNS全体から検索</label>
1546 <div>
1547 EOF
1548 cgi_form searchart<<EOF
1549 <label>`cgi_text kwd`という語を含む記事を全部から検索</label>
1550 EOF
1551 cat<<EOF
1552 </div></div>
1553 EOF
1554 fi
1556 # Record access log
1557 [ -n "$1" ] && [ x"$1" != x"$user" ] && acclog user $1
1559 commission() { # $1=grp-rowid $2=user-rowid
1560 contenttype; echo
1561 err commission: "$@"
1562 gname=`getgroupbyid $1`
1563 echo "グループ $gname 管理者委任" \
1564 | _m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1565 if [ -n "$2" ]; then
1566 grp_reg_adm "$@"
1567 else
1568 echo "無効な指定です。普通のアクセスならここに来ないはず。"|html p
1569 fi
1571 listgroupbytable() {
1572 # $1=deffile $2...=condition
1573 tagline=`grep :tag: $1`; shift
1574 and="${1:+and }" where=${1:+where }
1575 href="<a href=\"$myname?grp+"
1576 echo '<div class="listgroup">'
1577 NGsql="select distinct tag from\
1578 (select gname, max(case key when 'tag' then val end) as tag, \
1579 max(case key when 'ctime' then val end) as ctime\
1580 from grp_s group by gname order by ctime);"
1581 sql="select val from grp_s where key='tag' $and$* group by val;"
1582 err ListGRP: query sql="$sql"
1583 for tag in `query "$sql"`
1584 do
1585 err ListGrp: tag=$tag
1586 tn=${tagline%%=${tag}*}
1587 tn=${tn##*[ :]}
1588 sql="select rowid||':'||gname as 'グループ名',説明 from
1589 (select (select rowid from grp g where g.gname=grp_s.gname)
1590 as rowid,
1591 gname,
1592 max(case key when 'gecos' then val end) as '説明',
1593 max(case key when 'tag' then val end) as 'tag',
1594 max(case key when 'mtime' then val end) as mtime from grp_s
1595 $where$* group by gname having tag='$tag' order by mtime desc);"
1596 err PersonalGroupList= `echo $sql`
1597 echo "<h2>$tn</h2>"
1598 echo '<table class="b listgroup">'
1599 sq -header -html $db "$sql" \
1600 | sed "s,\(<TR><TD>\)\([0-9]*\):\([^ ]*\)</TD>,\1$href\2\">\3</a>,"
1601 echo '</table>'
1602 done
1603 echo '</div>'
1605 iconhref() (
1606 # $1=icon-file, $2=Href $3=title $4...=anchor
1607 data=`percenthex $1`
1608 ct=`file --mime-type $1|cut -d' ' -f2`
1609 err iconhref: \$1=$1 \$2=$2 \$3="$@"
1610 href=$2; title=$3; shift 3
1611 echo "<a href=\"$href\"><img title=\"$title\" src=\"data:$ct,$data\">$@</a>"
1613 iconhref2() (
1614 # $1=icon-file, $2=Href $3=title $4...=anchor
1615 src=$1
1616 href=$2; title=$3; shift 3
1617 echo "<a href=\"$href\"><img title=\"$title\" src=\"$src\">$@</a>"
1619 listentry() (
1620 # $1=user/group $2=SearchKeyword $3=condition(if any)
1621 # Referring variable $iamowner=$grp to attach owner-request links
1622 err listentry: \$1=$1 \$2=$2 \$3=$3
1623 cond=''
1624 offset=`getpar offset`
1625 offset=${offset%%[!0-9]*}
1626 offset=$((offset + 0)) # change to numeric forcibly
1627 [ $offset -lt 0 ] && offset=0
1628 limit=30
1629 dir=`getcachedir "$1"`
1630 if [ x"$1" = x"user" ]; then
1631 hrb="$myname?home"
1632 deficon=person-default.png
1633 entity="ユーザ" tbl=user link=rowid nm=name stage=mems
1634 gcs=gecos
1635 else # if group
1636 hrb="$myname?grp"
1637 deficon=group-default.png
1638 entity="グループ" tbl=grp link=rowid nm=gname stage=grps
1639 gcs=name
1640 tagline=`grep :tag: $formdir/grp.def|cut -d: -f5-`
1641 if [ -n "$tagline" ]; then
1642 tagconv=`echo $tagline|sed 's/\([^= :]*\)=\([^= :]*\)/-D\2=\1/g'`
1643 err tagconv=$tagconv
1644 fi
1645 fi
1646 if [ ! -d $dir ]; then
1647 mkdir -p $dir
1648 fi
1649 if [ ! -s $dir/$deficon ]; then
1650 convert -geometry $thumbxy $imgdir/$deficon $dir/$deficon
1651 fi
1652 if [ -n "$2" ]; then
1653 cond="where nick like '%$2%' or b.name like '%$2%'"
1654 fi
1656 # XX: これ複雑すぎるかな。もっとシンプルにしたい。$3条件も。2015-07-08
1657 # grpは呼出し元の動的スコープ変数でよくないな...
1658 ##qgrp=`sqlquote $grp`
1659 getgrp="(select gname from grp where rowid=${rowid:--1})"
1660 sql="select a.rowid, a.$link,
1661 coalesce(b.$gcs, a.$nm) as nick,
1662 coalesce(b.gecos, a.$nm) /* If group, concat (Nusers) */
1663 || case when a.$nm in (select gname from grp)
1664 then printf('(%d名)',
1665 (select count(user) from grp_mem where gname=a.$nm))
1666 else ' <'||a.$nm||'>'
1667 end
1668 as name,
1669 b.tag,
1670 case when a.$nm in (select user from grp_adm
1671 where gname=$getgrp) then '(管理者)'
1672 when '$user' in (select user from grp_adm where gname=a.$nm)
1673 then '(ADMIN)'
1674 when '$user' in (select user from grp_mem where gname=a.$nm)
1675 then '(Member)'
1676 when '$iamowner' = '' then ''
1677 else ',not='||a.rowid end as ownerlink
1678 from $tbl a left join
1679 (select $nm as name,
1680 max(case key when 'gecos' then val end) as gecos,
1681 max(case key when 'tag' then val end) as tag
1682 from ${tbl}_s group by $nm)
1683 b on a.$nm=b.name $cond $3
1684 order by b.tag desc, a.rowid asc"
1685 err LE:sql.1="$sql"
1686 total=`query "with x as ($sql) select count(*) from x;"`
1687 echo "${entity} 一覧" | html h2
1688 if [ $total -gt $limit ]; then
1689 echo '<div class="right">'
1690 cgi_form $stage <<EOF
1691 <label>次の語を含む${entity}で検索:
1692 `cgi_text kwd $kwd`</label>
1693 EOF
1694 echo '</div>'
1695 fi
1696 cat<<EOF
1697 <p>${total}件中の$((offset+1))件めから${kwd:+" - 検索語: $kwd"}</p>
1698 EOF
1699 if [ $((offset+limit)) -lt $total ]; then
1700 nextbtn=$(
1701 cat<<EOF
1702 <div class="right clear"><form action="$myname" method="POST">
1703 `cgi_submit 次の${limit}件`
1704 `cgi_hidden kwd "$kwd"`
1705 `cgi_hidden stage "$stage"`
1706 `cgi_hidden offset $((offset + limit))`</form></div>
1707 EOF
1709 fi
1710 if [ $offset -gt 0 ]; then
1711 prevbtn=$(
1712 cat<<EOF
1713 <form action="$myname" method="POST">
1714 `cgi_submit 前の${limit}件`
1715 `cgi_hidden stage "$stage"`
1716 `cgi_hidden kwd "$kwd"`
1717 `cgi_hidden offset $((offset - limit))`</form>
1718 EOF
1720 fi
1721 pnbtn="$nextbtn$prevbtn"
1722 echo $pnbtn
1724 err ListEntry: `echo "$sql"\;`
1726 query "$sql limit $limit ${offset:+offset $offset};" \
1727 | while IFS='|' read id lnk name gecos tag ownerp; do
1728 err name=$name owner=$ownerp lnk=$lnk
1729 err newlnk=$lnk
1730 icondir=$dir/$id
1731 files=`getvalbyid $tbl profimg $id $icondir`
1732 # Pick up only first icon
1733 echo "<div class=\"iconlist xy$thumbxy\"><p class=\"tag _$tag\">$tag</p>" \
1734 | _m4 $tagconv
1735 if [ -n "$files" ]; then
1736 icon=`echo "$files"|head -1`
1737 iconhref2 $icondir/$icon "$hrb+$lnk" "$gecos"
1738 else
1739 iconhref $dir/$deficon "$hrb+$lnk" "$gecos"
1740 fi
1741 echo "<br>$name${ownerp:+<br>$ownerp}"
1742 echo "</div>"
1743 done
1744 echo ${pnbtn:+"<hr>$nextbtn$prevbtn"}
1746 listmember() {
1747 listentry user "$@"
1749 listgroup() {
1750 listentry group "$@"
1752 hexteams() { # $1=gname, $2(optional)=user
1753 cond=${2:+" AND user='$2'"}
1754 query "SELECT DISTINCT hex(val) FROM grp_mem_m
1755 WHERE gname='$1' AND key='team'$cond;"
1757 showgroup() { # $1=group-rowid
1758 # gname=`getpar gname`
1759 # if [ -n "$gname" ]; then
1760 # err UPdating/Removing of group:::::::
1761 # # See ALSO same job in groupman()
1762 # newgname=`echo "$gname"|tr -d '\"'"'"`
1763 # ###newgname=$gname
1764 # err gname=$gname newgname=$newgname
1765 # if [ x"$newgname" != x"$gname" ]; then
1766 # err NewGNAME: gname=$newgname
1767 # gname=$newgname
1768 # echo "使用禁止文字を除去し $gname としました。" | html p
1769 # replpar gname string "$gname"
1770 # fi
1771 # par2table $formdir/grp.def
1772 # fi
1773 grp=`getgroupbyid $1`
1774 err showgroup2: grp=$grp qgrp="[$(sqlquote $grp)]"
1775 if isgroup "$grp"; then
1776 tf=$tmpd/title.$$
1777 echo "グループ $grp" > $tf
1778 showgroupsub $formdir/grp.def "$1" | \
1779 _m4 -D_TITLE_="spaste(\`$tf')" \
1780 -D_FORM_="syscmd(\`cat')" \
1781 -D_DUMPTABLE_="" \
1782 $layout/form+dump.m4.html
1783 else # if $grp is removed at par2table
1784 listgroup
1785 fi
1787 showgroupsub() {
1788 # $1=def-file $2=group-rowid
1789 rowid=$2
1790 grp=`getgroupbyid $2`
1791 qgrp=`sqlquote $grp`
1792 #rowid=`sq $db "select rowid from grp where gname=$qgrp"`
1793 if [ -z "$rowid" ]; then
1794 #rowid=`sq $db "select rowid from grp where rowid=$grp"`
1795 #grp=`sq $db "select gname from grp where rowid=$grp"`
1796 echo "showgroupsub: invalid argument($1 $2)" | html p
1797 return
1798 fi
1799 val=`getvalbyid grp profimg $rowid $tmpd`
1800 # 6/14の次グループのHOMEで出す情報を作る Done
1801 viewtable $1 grp $rowid
1802 if isgrpowner "$user" "$grp"; then
1803 echo "<p><a href=\"?groupconf+$rowid\">グループ情報の編集</a>"
1804 iamowner=$rowid
1805 fi
1806 if ismember "$user" "$grp"; then
1807 echo "${iamowner:+ / }<a href=\"?blog+$rowid\">グループの新規話題作成</a>"
1808 echo "/ <a href=\"?grpaction+$rowid\">メンバーを個別選択しての操作</a></p>"
1809 # div.fold input[type="checkbox"]:checked ~ div {display: block;}
1810 cat<<EOF
1811 <form action="?send2mem" method="POST" enctype="multipart/form-data">
1812 <div class="fold">
1813 `cgi_checkbox send yes id="send"`<label
1814 for="send">グループ全員にメッセージ送信</label>
1815 <div>
1816 `cgi_textarea message "" "cols=60"`
1817 `cgi_submit 送信`
1818 `cgi_reset リセット`
1819 </div>
1820 `cgi_hidden grp $rowid`
1821 </div></form>
1822 EOF
1823 fi
1824 # 加入ボタン + 加入者リスト
1825 err ismember $user $grp
1826 ismember "$user" "$grp" && ismem='checked' || nomem='checked'
1827 # このグループでの加入アドレス
1828 eml=`query "select val from grp_mem_s where gname=$qgrp and user='$user' \
1829 and key='email';"`
1830 err EML: "select val from grp_mem_s where gname='$2' and user='$user' \
1831 and key='email';"
1832 err email=$eml
1833 cat <<EOF
1834 <div class="fold">
1835 `cgi_checkbox reg yes id="reg"`<label
1836 for="reg">自身の参加状態を操作する</label>
1837 <div>
1838 EOF
1839 cgi_form grp <<EOF
1840 <p>このグループに</p>
1841 <table class="b">
1842 <tr><th>メンバーとして</th><td>
1843 <label>`cgi_radio joingrp "yes" $ismem`参加</label> /
1844 <label>`cgi_radio joingrp "no" $nomem`参加しない</label></td></tr>
1845 <tr><th>参加する場合のメイルアドレス<br>
1846 <small>(メインのアドレスとは違うものにする場合に記入<br>
1847 同じでよい場合は空欄に)</small></th>
1848 <td>`cgi_text email $eml`</td></tr>
1849 </table>
1850 `cgi_hidden grp $rowid`
1851 EOF
1852 if [ x`getgroupattr $grp regmode` = x'moderated' -a -z "$ismem" ]; then
1853 echo "moderated (承認加入の)グループなので実際に参加できるのは
1854 グループ管理者が承認操作をした後になります。" | html p 'class="warn"'
1855 fi
1856 echo '</div></div>'
1857 echo '<h2>話題一覧</h2>'
1858 cgi_form searchart<<EOF
1859 <label>`cgi_text kwd`という語を含むコメントを検索</label>
1860 `cgi_hidden owner $grp`
1861 EOF
1862 cond="where a.id in (select id from blog_s where key='owner' and val=$qgrp) order by ctime desc"
1863 DT_CHLD=article:blogid \
1864 DT_VIEW=replyblog dumptable html blog 'ctime team title heading' "$cond"
1866 getgname="(select gname from grp where rowid=$rowid)"
1867 c="group by b.name having b.name in (select user from grp_mem where gname=$getgname)"
1868 cm="?commission+$rowid"
1869 thumbxy=50x50 listmember "" "$c" \
1870 |sed -e "s|\(<br>\),not=\(.*\)|\1|" # 間違って押しやすい
1871 # team list
1872 hexteams=`hexteams "$grp"`
1873 if [ -n "$hexteams" ]; then
1874 echo "チーム一覧" | html h2
1875 echo '<div class="dumptable"><table class="b">'
1876 sq $db -html -header<<-EOF
1877 SELECT val TEAM,
1878 group_concat((SELECT gecos FROM gecoses WHERE name=user), ',')
1879 MEMBERS
1880 FROM grp_mem_m WHERE gname=$qgrp AND key='team' GROUP BY val;
1881 EOF
1882 echo '</table></div>'
1883 fi
1885 grpaction() { # $1=group-rowid
1886 err GRP_ACTION:IN
1887 grid=${1:-`getpar grp`}
1888 grp=`getgroupbyid "$grid"`
1889 if [ -z "$grp" ]; then
1890 echo "無効な指定です。" | html p; return
1891 fi
1892 if ! ismember $user $grp; then
1893 echo "加入者のみに許可された操作です。" | html p; return
1894 fi
1895 echo "グループ $grp 個別選択操作" \
1896 | _m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1898 isowner=""
1899 isgrpowner "$user" "$grp" && isowner="yes"
1900 usel=`getpar usel`
1901 if [ -n "$usel" ]; then
1902 uids=$(echo `echo $usel`|tr ' ' ',')
1903 err grpaction-1: grp=$grp, `echo $sql`
1904 text=`getpar text`
1906 rm=`getpar rm` cfm=`getpar confirm`
1907 err rm=$rm cfm=$cfm
1908 if [ x"$rm" = x"yes" ]; then
1909 if [ "$isowner" ]; then
1910 if [ x"$rm$cfm" = x"yesyes" ]; then
1911 # Eliminate
1912 cond="where gname=(select gname from grp where rowid=$grid) and user in (select name from user where rowid in ($uids))"
1913 for tbl in grp_mem grp_mem_s grp_mem_m; do
1914 sql="delete from $tbl $cond;"
1915 # echo "sql=$sql"
1916 query "$sql"
1917 err rmGRPuser "$sql"
1918 done
1919 num=`query "select count(*) from user where rowid in ($uids);"`
1920 #err num=$num
1921 if [ 0$num -gt 0 ]; then
1922 sql="select coalesce(b.val,a.name) from user a left join \
1923 user_s b on a.name=b.name and key='gecos' where a.rowid in ($uids);"
1924 # err `echo "$sql"`
1925 html pre<<EOF
1926 以下の${num}名のグループ $grp 登録を解除しました。
1927 `query "$sql"`
1928 EOF
1929 fi
1930 else
1931 echo "確認のチェックがないのでやめておきます。" | html p
1932 return
1933 fi
1934 else # not Group Owner
1935 echo "グループ管理者でないのでメンバー操作はできません。" | html p
1936 return
1937 fi
1938 cat<<EOF
1940 EOF
1941 elif [ x"$rm" = x"send" ]; then # if sendmsg mode
1942 if [ -z "$text" ]; then # if msg is empty
1943 echo "なにかメッセージを..." | html p
1944 return 0
1945 fi
1946 smail "`email4groupbyuid "$grp" $usel` $user" \
1947 "`gecos $user` さんからのメッセージ" <<EOF
1948 $url
1949 のグループ「$grp」のメンバーである `gecos $user` さんから、
1950 あなた宛へのメッセージです。
1951 ----------------------------------------------------------
1952 $text
1953 EOF
1954 if [ $? = 0 ]; then
1955 echo "Note: 以下のメンバーにメッセージを送信しました。" | html p
1956 sql="select coalesce(b.val, a.name) from
1957 (select name from user where rowid in ($uids)) a
1958 left join user_s b on a.name=b.name and b.key='gecos';"
1959 html pre<<EOF
1960 `query "$sql"`
1961 (送信者である `gecos $user` さんも含まれます)
1962 EOF
1963 err SendDone: `echo $sql`
1964 fi
1965 elif [ x"$rm" = x"commission" ]; then
1966 grp_reg_adm $grid $usel
1967 elif [ x"$rm" = x"addteam" ]; then
1968 team=`getpar team|sed "s/'/''/g"` # for single quotation
1969 newteam=`echo "$team"|tr -d ,`
1970 if [ x"$team" != x"$newteam" ]; then
1971 echo "チーム名に使えない文字を除去しました" | html p
1972 team=newteam
1973 fi
1974 if [ -z "$team" -o x"$team" = x"なし" ]; then
1975 cat<<-EOF | html p
1976 有効なチーム名を入力してください。
1977 カンマだけ、「なし」という名前は使えません。
1978 EOF
1979 echo "有効なチーム名を入力してください。" | html p
1980 else
1981 grp_add_team $grid "$team" $usel
1982 fi
1983 elif [ x"$rm" = x"rmteam" ]; then
1984 if [ x"yes" = x"`getpar teamconfirm`" ]; then
1985 rmteam=`getpar rmteam|sed "s/'/''/g"`
1986 if [ -n "`query \"SELECT val FROM grp_mem_m WHERE\
1987 gname='$grp' AND user='$user' AND key='team'\
1988 AND val='$rmteam';\"`" ]; then
1989 grp_rm_team $grid "$rmteam" $usel
1990 else
1991 echo "所属していないチームの除去操作はできません。"|html p
1992 fi
1993 else
1994 echo "確認チェックなしなのでチーム除去しませんでした。"|html p
1995 fi
1996 fi
1997 fi
1998 # New entry
1999 sql="select /* Ahh, ugly SQL, I wanna fix... */
2000 case
2001 when (select user from grp_adm where
2002 gname=(select gname from grp where rowid=$grid)
2003 and user=a.name) is not null
2004 then 'k'
2005 else ''
2006 end || a.rowid||
2007 ','||coalesce(val,a.name) as name,
2008 (SELECT group_concat(val, ',')
2009 FROM grp_mem_m
2010 WHERE gname='$grp' AND user=a.name AND key='team') as TEAM
2011 from
2012 (select rowid,name from user where name in
2013 (select user from grp_mem where
2014 gname=(select gname from grp where rowid=$grid)))
2015 a left join user_s on a.name=user_s.name and key='gecos'
2016 order by coalesce(val,a.name);"
2017 err grpaction: `echo "$sql"`
2018 tf=$tmpd/title.$$
2019 echo "グループ[<a href=\"?grp+$grid\">$grp<a>]参加メンバーに対する操作" > $tf
2020 cmmsg="<div class=\"fold\">
2021 `cgi_radio rm commission id=\"cmadmin\"`<label
2022 for=\"cmadmin\">下でチェックした人にグループ管理者委任</label>
2023 <div><p>このグループでの全権を付与します。信頼できる人に託してください。
2024 </p></div></div>"
2025 excmsg="<div class=\"fold\">
2026 `cgi_radio rm yes `下でチェックした人のグループ登録解除
2027 <div>
2028 本当に消します! `cgi_checkbox confirm yes` 確認
2029 <p>この操作による通知は本人に行きません。
2030 あらかじめ通知するか、登録解除してよい状況かしっかり確認してください。</p>
2031 </div>
2032 </div>"
2033 # Get team list to which current user belongs into $hexteams
2034 myhexteams=$(hexteams "$grp" "$user")
2035 allhexteams=$(hexteams "$grp")
2036 if [ -n "$myhexteams" ]; then
2037 rmteammsg="<div class=\"fold\">
2038 `cgi_radio rm rmteam 'id=\"cmrmteam\"'`<label
2039 for=\"cmrmteam\">下でチェックした人からチーム属性を除去する</label>
2040 <div>チーム属性:`cgi_select_h rmteam \"2d2d2d\" $myhexteams`
2041 を除去します: `cgi_checkbox teamconfirm yes` 確認
2042 <p>この操作による通知は本人に行きません。
2043 あらかじめ通知するか、登録解除してよい状況かしっかり確認してください。</p>
2044 </div>
2045 </div><!-- end of $rmteammsg -->
2047 fi
2048 b1='<label> <input type="checkbox" name="usel" value="'
2049 ba='<label class="admin"><input type="checkbox" name="usel" value="'
2050 #b2='"> <span>' b3='</span></label>'
2051 # | sed -e "s|^\(<TR><TD>\)k\([0-9]*\),\([^<]*\)|\1$ba\2$b2\3$b3|" \
2052 # -e "s|^\(<TR><TD>\)\([0-9]*\),\([^<]*\)|\1$b1\2$b2\3$b3|" \
2053 lnk='"> <span>\3</span></label> [<a href="?home+\2">HOME</a>]'
2054 cgi_form grpaction<<EOF \
2055 | sed -e "s|^\(<TR><TD>\)k\([0-9]*\),\([^<]*\)|\1$ba\2$lnk|" \
2056 -e "s|^\(<TR><TD>\)\([0-9]*\),\([^<]*\)|\1$b1\2$lnk|" \
2057 | _m4 -D_TITLE_="spaste(\`$tf')" \
2058 -D_SUBTITLE_="チェック後操作ボタン" \
2059 -D_FORM_="syscmd(cat)" -D_DUMPTABLE_="" \
2060 $layout/form+dump.m4.html
2061 <div class="fold">
2062 `cgi_radio rm addteam 'id="cmteam"'`<label
2063 for="cmteam">下でチェックした人に同じチーム属性を与える</label>
2064 <div>チーム名:`cgi_text team "" 'id="inteam" list="teams"'`
2065 `cgi_datalist_h teams $allhexteams`
2066 </div></div>
2067 ${rmteammsg}
2068 <div class="fold">
2069 `cgi_radio rm send id="sendmsg"`<label
2070 for="sendmsg">下でチェックした人にメッセージを送信する</label>
2071 <div>
2072 `cgi_textarea text "" cols=40`
2073 </div>
2074 </div>
2075 ${isowner:+$cmmsg$excmsg}
2076 <h4>$grp 参加者一覧</h4>
2077 <table>
2078 `sq $db -header -html "$sql"`
2079 </table>
2080 `cgi_hidden grp $grid`
2081 EOF
2083 crview4article() { # $1=rowid of blog, $2(optional)=extra SQL
2084 # Create TEMPORARY VIEW
2085 query<<EOF
2086 CREATE TEMPORARY VIEW writeusers AS
2087 SELECT DISTINCT author FROM article
2088 WHERE id in (
2089 select id from article where blogid=(select id from blog where rowid=$1)
2090 );
2091 CREATE TEMPORARY VIEW movablegroups AS
2092 SELECT g.rowid growid , g.gname
2093 FROM (SELECT grp.rowid, grp.gname FROM grp JOIN grp_mem gm
2094 ON grp.gname=gm.gname -- そのユーザが属している
2095 AND user='$user') g -- グループに絞る
2096 WHERE (SELECT author FROM writeusers
2097 EXCEPT
2098 SELECT user FROM grp_mem gm WHERE gm.gname = g.gname)
2099 IS NULL;
2100 $2
2101 EOF
2103 editheading() { # $1=rowid-of-heading
2104 rowid=${1%%[!A-Z0-9a-z_]*}
2105 if [ -z "$rowid" ]; then
2106 echo "話題番号が未指定です。" | html p
2107 return
2108 fi
2109 owner=`getvalbyid blog owner $rowid`
2110 title=`getvalbyid blog title $rowid`
2111 GF_ACTION="?blog" edittable $formdir/blog.def blog $rowid \
2112 | _m4 -D_TITLE_="修正" \
2113 -D_SUBTITLE_="[$title]@$owner" -D_DIARY_="" \
2114 -D_BLOGS_="" -D_DUMPTABLE_="" \
2115 -D_FORM_="syscmd(\`cat')" \
2116 $layout/html.m4.html $layout/form+dump.m4.html
2117 # Move to group
2118 if isuser "$owner"; then
2119 crview4article $rowid
2120 n=`query "SELECT count(*) FROM writeusers;"`
2121 err N=$n
2122 if [ $((n)) -gt 0 ]; then
2123 err ROWID=$rowid
2124 sql="SELECT growid || ':' || gname FROM movablegroups;"
2125 cat<<-EOF
2126 <div class="fold">
2127 `cgi_checkbox mv send id="mv"`<label
2128 for="mv">この話題をグループ所有に移動する</label>
2129 <div>
2130 <form action="?mvart" method="POST" enctype="multipart/form-data">
2131 移動先グループ:
2132 <select name="mv2grp">
2133 EOF
2134 query ".mode html"
2135 query<<-EOF |
2136 $sql
2137 .mode list
2138 EOF
2139 sed -e '/<\/TR>/d' -e 's,<TR>,,' -e 's,TD>,option>,g' \
2140 -e 's,n>\([0-9]*\):\(.*\)<,n value="\1">\2<,'
2141 cat<<-EOF
2142 </select>
2143 <p>(移動できるグループは、この「話題」に書き込んでいる人全てが
2144 そのグループに加入しているものに限られます)</p>
2145 <p>`cgi_checkbox cfm yes`<label>確認
2146 (この操作は元に戻すことができません)</label></p>
2147 `cgi_hidden blogrowid $rowid`
2148 `cgi_submit 移動`
2149 `cgi_reset Reset`
2150 </form>
2151 </div>
2152 </div>
2153 EOF
2154 fi
2155 # end of isuser "$owner"
2156 elif { hexteams=$(hexteams "$owner" ) # blog is of GROUP
2157 [ -n "$hexteams" ];}; then
2158 none="`echo なし|hexize`"
2159 cat<<-EOF
2160 <div class="fold">
2161 `cgi_checkbox mv2team send id="mv2team"`<label
2162 for="mv2team">この話題を以下のチームのものにする</label>
2163 <div><p>現在の所属チーム設定:
2164 `query "SELECT
2165 coalesce((SELECT val FROM blog_s
2166 WHERE id=(SELECT id FROM blog WHERE rowid=$rowid)
2167 AND key='team'),
2168 ':なし');"`</p>
2169 <form action="?mvart" method="POST" enctype="multipart/form-data">
2170 移動先チーム: `cgi_select_h mv2team $none $hexteams`
2171 <p>`cgi_checkbox cfm yes`<label>確認</label></p>
2172 `cgi_hidden blogrowid $rowid`<br>
2173 `cgi_submit 移動`
2174 `cgi_reset Reset`
2175 </form></div></div>
2176 EOF
2177 fi
2179 mvart() { # move diary to some group or team
2180 # or move blog of group to team which belong to the group
2181 blogrowid=`getpar blogrowid`
2182 cfm=`getpar cfm`
2183 ##### echo move blog:$blogrowid to $mv2grp | html p
2184 blogrowid=${blogrowid%%[!A-Z0-9a-z_]*} # Purify
2185 . ./s4-blog.sh
2186 if [ -z "$blogrowid" ]; then
2187 echo "無効な指定です(mvart)。" | html p
2188 return
2189 elif [ x"$cfm" != x"yes" ]; then
2190 echo "記事移動の確認にチェックがないので通常表示に戻ります。" | html p
2191 elif { mv2grp=`getpar mv2grp`
2192 mv2grp=${mv2grp%%[!A-Z0-9a-z_]*} # Purify
2193 [ -n "$mv2grp" ]; }; then
2194 crview4article $blogrowid
2195 ########## TRANSACTION BEGIN
2196 query "BEGIN;"
2197 n=`query "SELECT count(*) FROM writeusers;"`
2198 err Nwriteuser=$n
2199 if [ $((n)) -gt 0 ]; then
2200 query<<-EOF
2201 UPDATE blog_s SET val=(SELECT gname FROM grp WHERE rowid=$mv2grp)
2202 WHERE key='owner'
2203 AND id=(SELECT id FROM blog WHERE rowid=$blogrowid)
2204 AND $mv2grp IN (SELECT growid FROM movablegroups);
2205 EOF
2206 fi
2207 query "END;"
2208 ########## TRANSACTION END
2209 elif { mv2team=`getpar mv2team|sed "s/'/''/g"`
2210 [ -n "$mv2team" ];}; then
2211 # blog owner can move it to ANY team
2212 case "$mv2team" in
2213 'なし')
2214 cat<<-EOF
2215 DELETE FROM blog_s
2216 WHERE id=(SELECT id FROM blog WHERE rowid=$blogrowid)
2217 AND key='team';
2218 EOF
2219 ;;
2220 "") ;;
2221 *)cat<<-EOF
2222 BEGIN;
2223 REPLACE INTO blog_s(id, key, val)
2224 VALUES((SELECT id FROM blog WHERE rowid=$blogrowid),
2225 'team', '$mv2team');
2226 REPLACE INTO blog_s(id, key, val)
2227 VALUES((SELECT id FROM blog WHERE rowid=$blogrowid),
2228 'notify', 'all'); -- Change notify to all
2229 END;
2230 EOF
2231 esac | query
2232 fi
2233 blog_reply $blogrowid
2234 echo yes | html p
2236 editart() { # $1=article-rowid $2=blogrowid
2237 rowid=${1%%[!A-Z0-9a-z_]*}
2238 blogrowid=${2%%[!A-Z0-9a-z_]*}
2239 if [ -z "$rowid" -o -z "$blogrowid" ]; then
2240 echo "表示する記事番号が未指定です。" | html p
2241 return
2242 fi
2243 owner=`getvalbyid blog owner $blogrowid`
2244 title=`getvalbyid blog title $blogrowid`
2245 author=`getvalbyid article author $rowid`
2246 err EDITart: owner=$owner, author=$author
2247 if isgrpowner $user $owner; then
2248 : EDIT OK
2249 elif [ x"$owner" != x"$user" -a x"$author" != x"$user" ]; then
2250 echo "本人か所有者しか編集できません." | html p
2251 return
2252 fi
2253 aid=`query "select id from article where rowid=$rowid;"`
2254 tmpout=$tmpd/editart.$$.out
2255 GF_ACTION="?replyblog+$blogrowid#$aid" \
2256 edittable $formdir/article.def article $rowid \
2257 > $tmpout
2258 rm -f /tmp/editart.out
2259 # Cannot use pipelining to m4 with genform() because of stdin stack
2260 _m4 -D_TITLE_="コメントの修正" -D_DIARY_="" \
2261 -D_FORM_="syscmd(cat $tmpout)" \
2262 -D_SUBTITLE_="`gecos $owner`の「$title」" \
2263 -D_BLOGS_= -D_DUMPTABLE_= \
2264 $layout/html.m4.html $layout/form+dump.m4.html
2266 send2mem() {
2267 rowid=`getpar grp`
2268 if [ -z "$rowid" ]; then
2269 echo "グループが未指定です。" | html p
2270 return
2271 fi
2272 message=`getpar message`
2273 if [ -z "$message" ]; then
2274 echo "文章を入れてください。" | html p
2275 return
2276 fi
2277 grp=`getgroupbyid $rowid`
2278 members=`collectemail $grp`
2279 # smail rcpt subj (file)
2280 smail "$members" "グループ $grp 宛メッセージ(from `gecos $user`)" <<EOF
2281 $urlbase?grp+$rowid
2282 グループ $grp に所属する
2283 `gecos $user` さんよりメッセージ:
2285 $message
2286 EOF
2287 cat<<EOF
2288 <p>以下の宛先に送信しました。</p>
2289 <pre>
2290 $members
2291 </pre>
2292 <p><a href="?grp+$rowid">グループ $grp</a>に戻る。</p>
2293 EOF
2295 joingrpadmit() {
2296 # $1=yes/no $2=session-key
2297 if [ -z "$2" ]; then
2298 echo "bye bye" | html p; return
2299 fi
2300 t_usr=`session=$2 getpar user`
2301 t_grp=`session=$2 getpar group`
2302 err joingrpadmit: t_usr=$t_usr, t_grp=$t_grp
2303 _m4 -D_TITLE_="joingrp" $layout/html.m4.html
2304 if [ -z "$t_usr" -o -z "$t_grp" ]; then
2305 echo "無効な加入依頼です。" | html p
2306 echo "有効期限が切れたか、
2307 他の管理者がいる場合は処理済みの可能性があります。" | html p
2308 return
2309 fi
2310 if ! isgrpowner "$user" $t_grp; then
2311 echo "グループ管理者のみの機能です。" | html p; return
2312 fi
2313 case $1 in
2314 yes) joingrp "$t_grp" "$t_usr" yes "$t_usr" ;;
2315 no) joingrp "$t_grp" "$t_usr" no "$t_usr" ;;
2316 *)
2317 echo "無効な指定です($1)。" | html p
2318 return ;;
2319 esac
2320 gid=$(query "select rowid from grp where gname=`sqlquote $t_grp`;")
2321 rcpts="`getgroupadminmails $t_grp` $user"
2322 err admit: msgdir=$msgdir, rcpts="["$rcpts"]"
2323 body="グループ $t_grp
2324
2325 $t_usr
2326 `[ x$1 = xyes ] && echo 'を追加' || echo 'の解除操作を'`
2327 しました。"
2328 (echo "$body"; echo; echo "$url?grp+$gid") | smail "$rcpts" "joingrp $1"
2329 query "delete from session where id='$2';"
2330 echo "$body" | html p
2333 joingrprequest() {
2334 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
2335 jss="joingrp-`date +%s`-`genrandom 12`"
2336 addsession $jss +${memoplimitdays}days
2337 query "replace into par values('$jss', 'group', 'string', `sqlquote $1`),
2338 ('$jss', 'user', 'string', `sqlquote $user`);"
2339 smail "$(collectemail `getgroupadmins $1`)" "Join request to $1"<<EOF
2340 $url
2341 グループ $1
2342 に加入依頼がありました。
2344 承認する:
2345 $urlbase?joingrpadmit+yes+$jss
2347 白紙に戻す:
2348 $urlbase?joingrpadmit+no+$jss
2349 EOF
2350 echo "管理者に加入依頼を出しました。
2351 ${memoplimitdays}日以内に加入承認操作がされれば加入できますが、
2352 グループ運用方針に懸かることですので直接の問い合わせが重要です。" | html p
2354 joingrp() {
2355 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
2356 err joingrp: \$1=$1 \$2=$2 \$3=$3 \$4=$4
2357 if isgrpowner "$user" "$1"; then
2358 isowner="yes"
2359 elif [ -n "$5" ]; then
2360 isowner="yes"
2361 else
2362 isowner=""
2363 fi
2364 err jg:isgrpowner: isowner="$isowner"
2365 if [ -n "$isowner" ]; then
2366 : # GROUP OWNER CAN DO EVERYTHING ABOUT REGISTRATION/RETIREMENT
2367 elif [ x"$2" != x"$user" ]; then # if user is not login user
2368 echo "本人か、グループ管理者しか加入操作はできません。" | html p
2369 return
2370 elif [ x"$3" = x"no" ]; then
2371 : # Do not pursue those who leave
2372 else # adding user is $user itself
2373 case `getgroupattr $1 regmode` in
2374 moderated)
2375 joingrprequest "$@" # Request only
2376 return
2377 ;;
2378 *)
2379 ;;
2380 esac
2381 fi
2382 qgname=`sqlquote $1`
2383 cond="where gname=$qgname and user='$2'"
2384 if [ x"$3" = x"yes" ]; then
2385 query "replace into grp_mem values($qgname, '$2');"
2386 if [ -n "$4" ]; then
2387 if msg=`emaildomaincheck "$4"`; then
2388 err "replace into grp_mem_s values($qgname, '$user', 'email', \
2389 'string', '$4', NULL);"
2390 query "replace into grp_mem_s values($qgname, '$user', 'email', \
2391 'string', '$4', NULL);"
2392 if [ -n "$5" ]; then # as ADMIN
2393 # Coming here means newly created group
2394 sql="select case\
2395 when (select count(*) from grp_mem where gname=$qgname)=1\
2396 then (select user from grp_mem\
2397 where gname=$qgname and user='$user')\
2398 else '' end;"
2399 err NewGrpChk: $sql
2400 if [ -n "`query \"$sql\"`" ]; then
2401 err ADMIN: "replace into grp_adm values($qgname, '$user');"
2402 query "replace into grp_adm values($qgname, '$user');"
2403 fi
2404 fi
2405 else
2406 echo $msg
2407 fi
2408 else
2409 query "delete from grp_mem_s $cond and key='email';"
2410 fi
2411 else
2412 query "delete from grp_mem $cond;
2413 delete from grp_mem_s $cond;
2414 delete from grp_mem_m $cond;"
2415 fi
2417 grp_add_team() (
2418 # $1=grp-rowid $2=team $3...=user-rowid(s)
2419 grp=`getgroupbyid $1`
2420 team=$2; shift; shift
2421 [ -z "$grid" -o -z "$team" -o -z "$1" ] && return
2422 { echo "BEGIN;"
2423 for user; do
2424 echo "REPLACE INTO grp_mem_m(gname, user, key, type, val) VALUES(\
2425 '$grp',\
2426 (SELECT name FROM user WHERE rowid=$user),\
2427 'team', 'string', '$team');"
2428 done
2429 echo "END;"
2430 } | query
2432 grp_rm_team() (
2433 # $1=grp-rowid $2=team $3...=user-rowid(s)
2434 grid=$1
2435 qgrp=$(sqlquote "`getgroupbyid $grid`")
2436 team=$2; shift; shift
2437 [ -z "$grid" -o -z "$team" ] && return
2438 { echo "BEGIN;"
2439 for user; do
2440 echo "DELETE FROM grp_mem_m\
2441 WHERE gname=$qgrp \
2442 AND user=(SELECT name FROM user WHERE rowid=$user)\
2443 AND key='team' AND val='$team';"
2444 done
2445 cat<<-EOF
2446 DELETE FROM blog_s
2447 WHERE rowid=(
2448 SELECT rowid
2449 FROM blog_s a
2450 WHERE key='team'
2451 AND id IN (SELECT id FROM blog_s WHERE key='owner' AND val=$qgrp)
2452 AND NOT EXISTS (SELECT * FROM grp_mem_m
2453 WHERE key='team' AND val=a.val -- a.val=team
2454 AND gname = (SELECT val FROM blog_s b
2455 WHERE a.id=b.id AND key='owner')
2456 ));
2457 EOF
2459 echo "END;"
2460 } | query
2462 grp_reg_adm() {
2463 # $1=grp-rowid $2...=user-rowid
2464 grid=$1
2465 grp=`getgroupbyid "$1"`
2466 if [ -z "$grp" ]; then
2467 echo "無効なグループIDです" | html p; return
2468 fi
2469 if ! isgrpowner $user "$grp"; then
2470 echo "$grp グループの管理者しかこの操作はできません。" | html p; return
2471 fi
2472 shift
2473 for urid; do
2474 newadm=`query "select name from user where rowid=$urid;"`
2475 if [ -z "$newadm" ]; then
2476 echo "指定ユーザIDがおかしいようです。" | html p; return
2477 fi
2478 err GRP_reg_adm: "replace into grp_adm values(`sqlquote $grp`, '$newadm');"
2479 err ismember $newadm $grp
2480 if ismember $newadm $grp; then
2481 # OK, go ahead
2482 getgname="(select gname from grp where rowid=$grid)"
2483 query "replace into grp_adm values($getgname, '$newadm');"
2484 # confirm insertion
2485 sql="select * from grp_adm where gname=$getgname and user='$newadm'"
2486 if [ -n "`query \"$sql;\"`" ]; then
2487 echo "追加完了: $newadm" | html p
2488 else
2489 echo "追加失敗($1 $urid)" | html p
2490 fi
2491 fi
2492 showgroup $grid
2493 done
2495 dumptable() {
2496 # $1=mode $2=Table $3=column-list-of-*_s(defaults to *) $4=conditions(if any)
2497 # textのフィールドだけ全てダンプにしたほうがいいか
2498 # $DT_VIEW sets link
2499 # 6/17の次: editリンクじゃなくてスレッドVIEWリンクでいいんちゃう?
2500 ### elink="<a href=\"$myname?edittable+$2+\\2\">EDIT</a>"
2501 VIEW=${DT_VIEW-replyblog}
2502 if [ -n "$VIEW" ]; then
2503 dvlink=" <a href=\"$myname?$VIEW+\\2\">VIE</a><a href=\"$myname?$VIEW+\\2#bottom\">W</a>"
2504 fi
2505 # $DT_CHLD=ChildTable:BindColumn
2506 if [ -n "$DT_CHLD" ]; then
2507 _t=${DT_CHLD%:*} _i=${DT_CHLD#*:}
2508 cntall="(select count($_i) from $_t where $_i=a.id)"
2509 cntnew="(select count(val) from ${_t}_s where key='ctime' \
2510 and id in (select id from $_t where $_i=a.id) \
2511 and val > coalesce((select time from acclog where \
2512 user='$user' and tbl='$2' and tblrowid=a.rowid),\
2513 '1970-01-01'))"
2514 cnt="$cntnew as '新着', $cntall as '総数',"
2515 dt_class=" td2r td3r"
2516 fi
2517 # Construct join expression
2518 eav="" scols=""
2519 pk=`gettblpkey $2`
2520 substr=${dumpcollen:+"substr(val, 0, $dumpcollen)"}
2521 substr=${substr:-val}
2522 for col in ${3:-`gettbl_s_cols $2`}; do
2523 case $col in
2524 gecos) scols="$scols${scols:+, }${col#}"
2525 continue ;; # built-in column name
2526 *:*) col=${col%:*} as=${col#*:} ;;
2527 *) as=${col} ;;
2528 esac
2529 eav=$eav${eav:+,}" max(case key when '$col' then $substr end) as $as"
2530 scols="$scols${scols:+, }b.$as"
2531 done
2532 #case author when '$user' then a.rowid else '---' end as ID,
2533 sql=${DT_SQL:-"select \
2534 a.rowid as LINK,\
2535 $cnt\
2536 $scols from $2 a left join\
2537 (select $pk,$eav,
2538 max(case key when 'owner'
2539 then (SELECT gecos FROM gecoses WHERE name=val) END) as gecos
2540 from ${2}_s c group by $pk) b on a.$pk=b.$pk $4;"}
2541 err SQL=`echo "$sql"`
2542 cat<<EOF | sed "s,\(<TR><TD>\)\([1-9][0-9]*\)</TD>,\1$elink$dvlink</TD>,"
2543 <div> <!-- for folding by check button (s4-funcs.sh:dumptable()) -->
2544 <div class="dumptable">
2545 <table class="b$dt_class">
2546 `sq -header -cmd ".mode $1" $db "$sql"`
2547 </table>
2548 </div> <!-- dumptable -->
2549 </div> <!-- for folding by check button (s4-funcs.sh:dumptable()) -->
2550 EOF
2553 par2table() (
2554 # copy current parameters of par into destination table
2555 # $1=definition-file
2556 # Using $user and $session
2557 # Return value:
2558 # 0: Stored successfully
2559 # 1: Insufficient fillings
2560 # 2: No permission to modify the record
2561 # 3: Invalid rowid
2562 # 4: SUCCESS to delete
2563 # 5: Stop deletion for lack of confirm check
2564 # 6: Password length too short
2565 # 7: Password mismatch
2566 # 8: Old password incorrect
2567 rowid=`getpar rowid`
2568 err ...........rowid=$rowid
2569 if [ ! -e $1 ]; then
2570 echo "テーブル定義ファイルが見付かりません" | html p
2571 exit 1
2572 fi
2573 tbl=${1%.def}
2574 tbl=${tbl##*/}
2575 if [ -n "$rowid" ]; then # Modify existing entry
2576 if [ x"$tbl" = x"user" ]; then
2577 rowowner=`query "select name from $tbl where rowid=$rowid;"`
2578 elif [ x"$tbl" = x"grp" ]; then
2579 sql="select gname from $tbl where rowid=$rowid;"
2580 ##err p2t:grp:q $sql
2581 isgrpowner $user "`query $sql`" && rowowner=$user
2582 else
2583 rowowner=`query "select owner from $tbl where rowid=$rowid;"`
2584 rowowner=${rowowner:-`query "select author from $tbl
2585 where rowid=$rowid;"`}
2586 fi
2587 ### err rowowner=$rowowner
2588 if [ x"$user" != x"$rowowner" ]; then
2589 echo "他人のレコードはいじれないの" | html p
2590 return 2
2591 elif [ -z "$rowowner" ]; then
2592 echo "指定したレコードはないみたい" | html p
2593 return 3
2594 fi
2595 rm=`getpar rm` cfm=`getpar confirm`
2596 # Editing existent entry
2597 if [ x"$rm" = x"yes" ]; then
2598 if [ x"$rm$cfm" = x"yesyes" ]; then
2599 query "delete from $tbl where rowid=$rowid;"
2600 return 4
2601 else
2602 echo "消去確認のチェックがないので消さなかったの..." | html p
2603 return 5
2604 fi
2605 fi
2606 fi
2607 # XX: Subshelling here is unnecessary 2015-07-05
2608 (ts=${tbl}_s tm=${tbl}_m val="" pval="" formaster=""
2609 if [ -n "$rowid" ]; then
2610 # Update of existing record
2611 for col in `gettblcols $tbl`; do
2612 val=`getparquote $col`
2613 [ -z "$val" ] && continue
2614 err query "update $tbl set $col=$val where rowid=$rowid"
2615 ## XX: THIS IS DIRTY hack to ensure non-foreign key in blog_s
2616 sql="update $tbl set $col=$val where rowid=$rowid;"
2617 if [ x"$tbl" = x"grp" -a x"$col" = x"gname" \
2618 -o x"tbl" = x"user" -a x"$col" = x"name" ]; then
2619 ## User name cannot be changed with interface provided with this
2620 ## script. But we offer the trigger to change owner user
2621 ## of blog_s table.
2622 err "select quote($col) from $tbl where rowid=$rowid;"
2623 old=`query "select quote($col) from $tbl where rowid=$rowid;"`
2624 cat<<-EOF | query
2625 BEGIN;
2626 $sql
2627 update blog_s set val=$val
2628 where key='owner' and val=$old;
2629 COMMIT;
2630 EOF
2631 ## XX: DIRTY Hack Ends here
2632 ## We should keep blog's owner as a single column which has
2633 ## foreign key constraint with primary key of grp/user.
2634 else
2635 query "$sql"
2636 fi
2637 done
2638 # Then, set up $pval for further insertion of tbl_s and tbl_m
2639 for col in `gettblpkey $tbl`; do
2640 val=`query "select $col from $tbl where rowid=$rowid;"|sed -e 's/\"/\"\"/g'`
2641 pval="$pval${pval:+, }\"$val\""
2642 done
2643 else
2644 # New entry
2645 # Generate values() for primary keys
2646 for col in `gettblpkey $tbl`; do
2647 # Genuine primary keys for _m and _s
2648 val=`getvalquote $tbl $col`
2649 [ -z "$val" ] && continue
2650 pval="$pval${pval:+, }$val"
2651 done
2652 err pval=$pval
2653 for col in `gettblfkey $tbl`; do
2654 # args for values() to insertion into master table
2655 val=`getvalquote $tbl $col`
2656 [ -z "$val" ] && continue
2657 formaster=$formaster"${formaster:+, }$val"
2658 done
2659 formaster="$pval${formaster:+, }$formaster"
2660 err formaster=$formaster
2661 if [ -z "$formaster" ]; then
2662 echo "項目を全て埋めてください" | html pre
2663 return 1
2664 fi
2665 err "replace into $tbl values($formaster);"
2666 query "replace into $tbl values($formaster);"
2667 ## Insertion to master table, done
2668 fi
2670 for kt in s m; do
2671 tb2=${tbl}_$kt
2672 for col in `gettbl_${kt}_cols $tbl`; do
2673 ptype=`getpartype $col "limit 1"`
2675 # First, check update of existing entries in _m
2676 if [ $kt = m ]; then
2677 # sessID|address.1.22|string|Somewhere-x.y.z
2678 sql=""
2679 err dots from query "select var from par where var like '$col.%';"
2680 for v in `query "select var from par where var like '$col.%';"`; do
2681 # v=address.1.22
2682 st_rowid=${v##*.}
2683 origcol=${v%%.*} # original column derived from
2684 err Updating for $v st_rowid=$st_rowid, partype=`getpartype $v`
2685 ##case `getpartype $v` in
2686 err CASE `gettbl_coltype $tbl/$origcol` in
2687 err edit flag = `getpar action.$v`
2688 case `getpar action.$v` in
2689 rm)
2690 if [ x`getpar confirm.$v` = x"yes" ]; then
2691 newsql="delete from $tb2"
2692 else
2693 echo "削除確認未チェック" | html p
2694 fi ;;
2695 edit)
2696 case `gettbl_coltype $tbl/$origcol` in
2697 image|document|binary)
2698 file=$tmpd/`getparfilename $v`
2699 err type=file=$file
2700 [ -z "$file" ] && continue
2701 bn=${file##*/}
2702 bin="X'"$(hexize $file)"'"
2703 ct=`file --mime-type $file|cut -d' ' -f2`
2704 type=\"file:$ct\"
2705 newsql="update $tb2 set val='$bn', type=$type, bin=$bin"
2706 cachedir=`getcachedir "$tbl/$rowid"`
2707 err getcache tbl/rowid=$tbl/$rowid, rm -r $cachedir
2708 rm -r $cachedir
2709 ;;
2710 *)
2711 newsql="update $tb2 set val=(select val from par where var \
2712 like '$col.%.$st_rowid')"
2713 ;;
2714 esac
2715 ;;
2716 *) # maybe "keep", do not modify value
2717 continue
2718 ;;
2719 esac
2720 # err newsql=$newsql
2721 sql=$sql$nl"$newsql where rowid=$st_rowid;"
2722 done
2724 if [ x"$bin" = x"NULL" ]; then
2725 err repl:normal sql=`echo $sql`
2726 query "$sql
2727 delete from $tb2 where type='string' and val='';"
2728 err repl:normal done
2729 else
2730 sqlfile="$tmpd/sqlf.$$"
2731 echo "$sql" > $sqlfile
2732 err repl:sqlfile=`ls -lF $sqlfile`
2733 query ".read $sqlfile"
2734 err repl:done
2735 fi
2736 # Rest of kt==m: set multiple mode
2737 nr=`getparcount $col`
2738 else
2739 nr=1 # for kt==s, number of records is 1
2740 fi
2742 i=0
2743 while [ $i -lt $nr ]; do
2744 limit="limit 1 offset $i"
2745 i=$((i+1)) # increase beforehand against continue
2746 val=`getvalquote $tbl $col "$limit"`
2747 [ -z "$val" -o x"$val" = x'""' -o x"$val" = x"NULL" ] && continue
2748 err $col=$val
2749 bin=NULL
2750 err partype$col=`getpartype $col "$limit"`
2751 case $ptype in
2752 file) file=$tmpd/`getparfilename $col "$limit"`
2753 err parfile-$col=$file
2754 [ -z "$file" ] && continue
2755 bin="X'"$(hexize $file)"'"
2756 ct=`file --mime-type $file|cut -d' ' -f2`
2757 type=\"file:$ct\" ;;
2758 "*"*) continue ;; # foreign table
2759 *) type=\"string\" ;;
2760 esac
2761 case `gettbl_coltype $tbl/$col` in
2762 password) # special care for password
2763 # name={password,pswd1,pswd2}
2764 p1=`getpar pswd1 "$limit"`
2765 if [ -z "$p1" ]; then
2766 continue # SKIP password setting, if p1 is empty
2767 else
2768 pswd=`getpar pswd "$limit"` p2=`getpar pswd2 "$limit"`
2769 ## err pswd=$pswd
2770 if pwcheck "$pswd"; then
2771 if [ x"$p1" = x"$p2" ]; then
2772 case "$p1" in
2773 ??????????*) ;;
2774 *) echo "パスワードは10字以上にしてください。" | html p
2775 return 6;;
2776 esac
2777 val="\"`echo $p1|mypwhash`\""
2778 else
2779 echo "2つの新パスワード不一致" | html p
2780 return 7
2781 fi
2782 else
2783 echo "旧パスワード違います" | html p
2784 return 8
2785 fi
2786 fi
2787 ;;
2788 esac
2789 err p2t: "replace into $tb2 values($pval, \"$col\", $type, $val, bin...);"
2790 #query "replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
2791 sql="replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
2792 if [ x"$bin" = x"NULL" ]; then
2793 err Normal-query: `echo $sql`
2794 query "$sql"
2795 else
2796 sqlfile="$tmpd/query.$$"
2797 echo "$sql" > $sqlfile
2798 err sqlfile=`ls -lF $sqlfile`
2799 query ".read $sqlfile"
2800 fi
2801 err p2t done
2802 done
2803 done
2804 done
2805 return 0
2806 err donee)
2808 par2table_old() {
2809 # copy current parameters of par into destination table
2810 # $1=dst-table $2=definition-file
2811 # Using $user and $session
2812 rowid=`getpar rowid`
2813 if [ -n "$rowid" ]; then
2814 rm=`getpar rm` cfm=`getpar confirm`
2815 if [ x"$rm$cfm" = x"yesyes" ]; then
2816 sq $db "delete from $1 where rowid=$rowid and owner=\"$user\""
2817 return
2818 fi
2819 fi
2820 cat $2 \
2821 | (cols=""
2822 while IFS=: read prompt name type args; do
2823 [ x"$name" = x"stage" ] && continue
2824 if [ -n "$rowid" ]; then
2825 val=`getpar $name|sed -e 's/\"/\"\"/g'`
2826 sq $db "update $1 set $name=\"$val\" where rowid=$rowid and owner=\"$user\""
2827 else
2828 eav=$eav${eav+,}" max(case var when '$name' then val end)"
2829 fi
2830 done
2831 [ -n "$rowid" ] && return
2832 cond="where sessid='$session' group by sessid"
2833 sq $db "replace into $1 select $eav,\"$user\" from par $cond"
2834 # Think over again about putting $user
2837 genform() {
2838 # $1 = form definition file
2839 # $2, $3 (optional)= table name and ROWID
2840 # If $GF_VIEWONLY set and nonNull, output values without form
2841 # If $GF_ARGS set, use it as content-strings in the form
2842 # If $GF_OWNER set, use it as value of name="owner"
2843 # If $GF_STAGE set, use it as value of name="stage"
2844 forms="" hiddens="" rowid=$3
2845 if [ ! -e "$1" ]; then
2846 echo "そのようなデータベースはないようです($2)。" | html p
2847 return
2848 elif [ -n "$2" ]; then
2849 err genform1: "select * from $2 where rowid='$rowid'"
2850 rec=`query "select * from $2 where rowid='$rowid';"`
2851 if [ -z "$rec" ]; then
2852 pk=`gettblpkey $2`
2853 ###rec=`sq $db "select rowid from $2 where $pk='$rowid'"`
2854 err "select rowid from $2 where $pk='$rowid';"
2855 rec=`query "select rowid from $2 where $pk='$rowid';"`
2856 err rec-rowid=$rec
2857 rowid=$rec
2858 rec=$3
2859 fi
2860 if [ -z "$rec" ]; then
2861 echo "そんなレコードはないみたいね..." | html p
2862 return
2863 fi
2864 fi
2865 if [ -z "$GF_VIEWONLY" ]; then
2866 rm='<input id="rm" name="rm" type="checkbox"
2867 value="yes"><label for="rm">このエントリの削除</label>
2868 <span>ほんとうに消しますよ(確認)!
2869 <input name="confirm" type=checkbox value="yes">はい</span>'
2870 fi
2871 # Image Cache dir
2872 err genform: getcache=$2/$rowid
2873 td=`getcachedir "$2/$rowid"`
2874 while IFS=: read prompt name keytype type args; do
2875 [ -z "${prompt%%\#*}" ] && continue # skip comment line(#)
2876 sp="${args:+ }"
2877 form="" val=""
2878 if [ -n "$rowid" ]; then
2879 # err genform2a: Seeking for "$2.$name, type=$type"
2880 val=`getvalbyid $2 $name $rowid $td|htmlescape`
2881 err genform3a: getvalbyid $2 $name $rowid $td
2882 err genform3b: val="[$val]"
2883 fi
2884 if [ -n "$GF_VIEWONLY" ]; then
2885 is_hidden "$2" "$name" && continue
2886 fi
2887 case "$type" in
2888 text*)
2889 cgiform=cgi_multi_$type
2890 if [ -s $td/$name.count -a -n "$val" ]; then
2891 form=`$cgiform $name $td`
2892 val=$(echo "$val"|
2893 while read fn; do
2894 echo "<tr><td>`cat $td/$fn|htmlescape|hreflink`
2895 </td></tr>$nl"
2896 done)
2897 val="<table>$nl$val$nl</table>"
2898 else
2899 #form="<input name=\"$name\" value=\"$val\" type=\"$type\"$sp$args>$nl"
2900 err genform: cgi_$type $name $val "$args"
2901 form=`cgi_$type $name "$val" "$args"`
2902 fi
2903 ;;
2904 [Rr][Aa][Dd][Ii][Oo])
2905 fh="<label><input type=\"radio\" name=\"$name\""
2906 form="`echo $args|sed -e \
2907 \"s,\([^ =][^=]*\)=\([^= ][^= ]*\),$fh value=\\"\2\\">\1</label>,g\"`"
2908 ;;
2909 [Cc][Hh][Ee][Cc][Kk][Bb][Oo][Xx])
2910 form="<label><input type=\"checkbox\" name=\"$name\" value=\"${args#*=}\">${args%=*}</label>"
2911 ;;
2912 [Ss][Ee][Ll][Ee][Cc][Tt])
2913 fh="<select name=\"$name\">$nl"
2914 form=$(for l in $args; do
2915 echo "<option value=\"${l#*=}\">${l%=*}</option>"
2916 done)
2917 if [ -n "$val" ]; then
2918 form=`echo $form|sed -e "s,\(value=.$val.\),\\1 selected,"`
2919 fi
2920 form="$fh$form</select>"
2921 ;;
2922 [Ii][Mm][Aa][Gg][Ee]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Bb]inary)
2923 if [ -s $td/$name.count ]; then
2924 form=`cgi_multi_file $name $td "$args"`
2925 if [ -n "$val" ]; then
2926 hrfb="$myname?showattc+$2_m"
2927 val=$(echo "$val" \
2928 | while read fn; do
2929 data=`percenthex $td/$fn`
2930 #ct=`cat $td/$fn.content-type`
2931 ct=`file --mime-type $td/$fn|cut -d' ' -f2`
2932 ri=`cat $td/$fn.rowid`
2933 ## err fn=$fn, name=$name, ri=$ri; ls -lF $td 1>&3
2934 #imgsrc="<img src=\"data:$ct,$data\">"
2935 #echo "<a href=\"$hrfb+$ri\">$imgsrc</a><br>"
2936 iconhref $td/$fn "$hrfb+$ri" ""
2937 done)
2938 fi
2939 else
2940 form="<input type=\"file\" name=\"$name\" $args>"
2941 if [ -n "$val" ]; then
2942 imgs=$(echo "$val"\
2943 |while read fn;do
2944 data=`percenthex $td/$fn`
2945 echo "<img src=\"data:image/png,$data\">$fn<br>"
2946 done)
2947 form=$form"<br>$imgs"
2948 val=$imgs # 2015-06-15
2949 else
2950 form="<input type=\"file\" name=\"$name\" $args>"
2951 fi
2952 fi
2953 ;;
2954 [Hh][Ii][Dd][Dd][Ee][Nn])
2955 if [ -n "$GF_STAGE" -a x"$name" = x"stage" ]; then
2956 args="value=\"$GF_STAGE\""
2957 fi
2958 form="<input type=\"hidden\" name=\"$name\" $args>"
2959 prompt='' # Remove prompt
2960 ;;
2961 [Aa][Uu][Tt][Hh][Oo][Rr])
2962 form="<input type=\"hidden\" name=\"author\" value=\"$user\">"
2963 prompt="" ;;
2964 [Oo][Ww][Nn][Ee][Rr])
2965 val=${GF_OWNER:-$val}
2966 val=${val:-$user}
2967 form="<input type=\"hidden\" name=\"owner\" value=\"$val\">"
2968 prompt="" ;;
2969 [Uu][Ss][Ee][Rr])
2970 # XXX: is null $user ok?
2971 #form="<input type=\"hidden\" name=\"user\" value=\"$user\">"
2972 [ -n "$GF_VIEWONLY" ] && continue
2973 form="$user"
2974 ;;
2975 [Pp]assword)
2976 [ -n "$GF_VIEWONLY" ] && continue
2977 form="`cgi_passwd`"
2978 val=""
2979 ;;
2980 [Ss][Ee][Rr][Ii][Aa][Ll]|[Ss][Tt][Aa][Mm][Pp])
2981 if [ -z "$rowid" ]; then
2982 val=$((($(date +%s)-1433084400)/10))c$$
2983 fi
2984 form="<input type=\"hidden\" name=\"$name\" value=\"$val\">"
2985 prompt="" ;;
2986 [Ss][Ee][Ss][Ss][Ii][Oo][Nn])
2987 prompt=""
2988 ;;
2989 parent|path|blog*)
2990 prompt=""
2991 ;;
2992 "*"*)
2993 tail=$tail"``"
2994 continue ;;
2995 esac
2996 if [ -n "$prompt" ]; then
2997 if [ -n "${GF_VIEWONLY}" ]; then
2998 form=$val
2999 else
3001 fi
3002 forms=$forms" <tr class=\"$name\"><th>$prompt</th><td>$form</td></tr>$nl"
3003 else
3004 hiddens=$hiddens$nl"$form"
3005 fi
3006 done < $1
3007 # enctype="multipart/form-data"
3008 cat<<EOF
3009 <form action="${GF_ACTION:-$myname}" method="POST" enctype="multipart/form-data">
3010 ${rowid:+$rm}
3011 <table class="b $2">
3012 $forms
3013 </table>$hiddens
3014 ${GF_STAGE:+`cgi_hidden stage $GF_STAGE`}
3015 ${rowid:+<input type="hidden" name="rowid" value="$rowid">}
3016 EOF
3017 if [ -z $GF_VIEWONLY ]; then
3018 cat<<EOF
3019 <input type="submit" name="sub" value="OK">
3020 <input type="reset" name="res" value="Reset">
3021 EOF
3022 fi
3023 cat<<EOF
3024 $GF_ARGS</form>
3025 $tail
3026 EOF
3028 edittable() {
3029 # $1=form-def $2=table $3 rowid
3030 genform "$@"
3032 viewtable() {
3033 GF_VIEWONLY=1 genform "$@"
3035 showattc() {
3036 # $1=table_m $2=rowid
3037 err \$1=$1 \$2=$2
3038 if ! isfilereadable $user $1 $2; then
3039 contenttype; echo
3040 echo "このファイルは管理者のみしか見られません" | html p
3041 putfooter; exit
3042 fi
3043 idir=`umask 002; mktempd` || exit 1
3044 # tmpfiles=$tmpfiles"${tmpfiles+ }$idir"
3045 bin=$idir/$myname-$$.bin
3046 sql="select quote(bin) from $1 where rowid='$2';"
3047 err showattc: sql: $sql
3048 sq $db "$sql" | unhexize > $bin
3049 tv=`query "select type,val from $1 where rowid='$2';"`
3050 type=${tv%\|*} fn=${tv#*\|}
3051 err tv=$tv type=$type fn=$fn, tp2=${tv%\|*}
3052 ct=${type#file:}
3053 case $ct in # all text/* changed to text/plain
3054 text/*)
3055 charset=`nkf -g $bin|cut -d' ' -f1`
3056 case $charset in
3057 ASCII*) charset="" ;;
3058 esac
3059 ct="text/plain${charset:+; charset=$charset}"
3060 ;;
3061 esac
3062 contenttype "$ct"
3063 echo "Content-Disposition: filename=\"$fn\""
3064 echo "Content-Length: " `cat $bin | wc -c`; echo
3065 #echo "Content-Type: " ${type#file:}; echo
3066 cat $bin
3069 # Some default stupid handler on CGI values
3071 default_storedb() {
3072 # ARG: $1=table-def-file
3073 # RET: $tbl=table-name, $col=mail-column, $cols=columns
3074 tbl=`basename $1`
3075 tbl=${tbl%.def}
3076 cols="`grep :text $1|cut -d: -f2`"
3077 col=`echo "$cols"|head -1`
3078 vcol=`getpar $col`
3079 err default0: \$1=$1 col=$col cols="[$cols]" vcol=$vcol
3080 if [ -n "$vcol" ]; then
3081 par2table $1
3082 else
3083 return 2 # No insertion occurred
3084 fi
3087 default_view() { # $1=def-file
3088 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
3089 ## DT_VIEW="edittable+$tbl" dumptable html $tbl "name memo file" \
3090 default_storedb "$@"
3091 query "select rowid from $tbl order by rowid desc;" \
3092 | while read rowid; do
3093 viewtable $1 $tbl $rowid
3094 done | _m4 -D_TITLE_="$tbl" \
3095 -D_FORM_="`genform $1`" \
3096 -D_DUMPTABLE_="syscmd(cat)" \
3097 $layout/html.m4.html $layout/form+dump.m4.html
3099 default_viewtext() { # $1=def-file
3100 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
3101 default_storedb "$@"
3102 DT_VIEW="viewtable+$tbl" dumptable html $tbl "name memo file" \
3103 | _m4 -D_TITLE_="$tbl" \
3104 -D_FORM_="`genform $1`" \
3105 -D_DUMPTABLE_="syscmd(cat)" \
3106 $layout/html.m4.html $layout/form+dump.m4.html
3108 default_smail() {
3109 default_storedb "$@"
3110 if [ $? -eq 2 ]; then
3111 _m4 -D_TITLE_="入力" \
3112 -D_FORM_="`genform $1`" \
3113 -D_DUMPTABLE_="" \
3114 $layout/html.m4.html $layout/form+dump.m4.html
3115 return
3116 fi
3117 cond=""
3118 for pk in `gettblpkey $tbl`; do
3119 pv=$(sqlquote $(getpar $pk))
3120 cond="$cond${cond:+ and }$pk=$pv"
3121 done
3122 sql="select rowid from $tbl where $cond;"
3123 rowid=`query "$sql"`
3124 err smail1 - "$sql" "-> rowid=$rowid"
3126 while IFS=: read prompt name keytype type args; do # Read from $1
3127 val=`getpar $name`
3128 if [ -n "$val" ]; then
3129 text="$text
3130 $prompt
3131 $name=$val
3132 ---------------------------------------------------------"
3133 fi
3134 case "$type" in
3135 image|document|file)
3136 fn="`getvalbyid $tbl $name $rowid $tmpd`"
3137 fns=$(echo "$fn"|while read fn; do
3138 err mv $tmpd/$fn.orig $tmpd/$fn
3139 mv $tmpd/$fn.orig $tmpd/$fn
3140 rm $tmpd/$fn.rowid # Remove cache flag
3141 err "`ls $tmpd/$fn`"
3142 echo $fn
3143 done)
3144 files="$files $fns"
3145 ;;
3146 esac
3147 done < $1
3148 err FILES=$files "`ls -lF $tmpd`"
3149 subj="from ${REMOTE_ADDR}"
3150 (echo "$url"
3151 echo "への書き込みがありました。"
3152 echo "------"
3153 echo "$text"
3154 ) | (cd $tmpd &&
3155 err LS="`ls -lF`" &&
3156 $mydir/sendmultipart.sh -t "$admin" -s "$subj" $files)
3157 _m4 -D_TITLE_="入力完了" $layout/html.m4.html
3158 echo "以下の内容で送信しました。" | html p
3159 viewtable $1 $tbl \
3160 `query "select rowid from $tbl order by rowid desc limit 1;"`
3161 echo "戻る" | html a "href=\"?\""