s4

view s4-funcs.sh @ 117:82e215e75468

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