s4

view s4-funcs.sh @ 228:ab1693ac909a

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