s4

view s4-funcs.sh @ 120:d870eaf0e4dd

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