s4

view s4-funcs.sh @ 142:ca6428b37dd2

Remove double-quotes in here-document
author HIROSE Yuuji <yuuji@gentei.org>
date Tue, 06 Oct 2015 21:56:30 +0859
parents 6da489b573ca
children d4abf37a5ea2
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 -a -s $file.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"}'|sed 's/BB/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 ## dd bs=$CONTENT_LENGTH count=1 of=$tmpf # NOT working
1037 # cat > $tmpf # too much?
1038 head -c $CONTENT_LENGTH > $tmpf # safe?
1039 (echo CL=$CONTENT_LENGTH; ls -lF $tmpf) 1>&3
1040 s="`cat tmp/stream`"
1041 tmpfiles=$tmpfiles"${tmpfiles+ }$tmpf"
1042 ;;
1043 esac
1044 case "$CONTENT_TYPE" in
1045 *boundary*)
1046 bndry=${CONTENT_TYPE#*boundary=}
1047 #for us in `LC_CTYPE=C ./mpsplit.rb "$bndry" $tmpd < $tmpf`
1048 for us in `LC_CTYPE=C ./mpsplit.pl "$bndry" $tmpd < $tmpf`
1049 do
1050 k=${us%%\=*}
1051 #echo u=$us
1052 #v="`echo ${us#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
1053 v="`echo ${us#*=}|unhexize|sed -e 's/\"/\"\"/g'`"
1054 # err k=$k v=$v
1055 case "$k" in
1056 *:filename)
1057 type='file'; k=${k%:filename}
1058 (echo k=$k; ls -lF $tmpd/$v; file --mime-type $tmpd/$v) 1>&3
1059 case `file --mime-type $tmpd/$v|cut -d' ' -f2` in
1060 [Ii]mage/x-xcf)
1061 bzip2 $tmpd/$v
1062 v=${v}.bz2
1063 ;;
1064 [Ii]mage/x-*|*/vnd.*) ;;
1065 [Ii]mage/*)
1066 mogrify -resize $maximagexy'>' $tmpd/$v
1067 ;;
1068 esac
1069 ;;
1070 *)
1071 type='string'
1072 ;;
1073 esac
1074 #sq $db "replace into par values('$session', '$k', '$type', \"$v\")"
1075 setpar "$k" "$type" "$v"
1076 done
1077 ;;
1078 *)
1079 setviastring par "$s"
1080 ;;
1081 esac
1083 email4group() {
1084 # Get for-$1=group email address(es) for $2...=users
1085 qgrp=`sqlquote "$1"`; shift
1086 users=`for i; do sqlquote "$i"; done`
1087 users=`echo $users|tr ' ' ','`
1088 sql="select coalesce(s.val, g.user) from grp_mem g
1089 left join grp_mem_s s on g.gname=s.gname and g.user=s.user
1090 and s.key='email'
1091 where g.gname=$qgrp and g.user in ($users);"
1092 err `echo $sql`
1093 query "$sql"
1095 email4groupbyuid() {
1096 # Get for-$1=group email address(es) for $2...=user-ids
1097 qgrp=`sqlquote "$1"`; shift
1098 err em4gbid-IN: "\$1=$1 qgrp=$qgrp"
1099 uids=`echo "$@"`
1100 uids=`echo $uids|tr ' ' ','`
1101 sql="select coalesce(s.val, g.user) from grp_mem g
1102 left join grp_mem_s s on g.gname=s.gname and g.user=s.user
1103 and s.key='email'
1104 where g.gname=$qgrp and g.user in
1105 (select name from user where rowid in ($uids));"
1106 err email4gByid `echo $sql`
1107 query "$sql"
1109 collectemail() (
1110 # Collect email addresses for group $1
1111 for e; do
1112 if isuser "$e"; then
1113 em=`query "select val from user_m where name='$e' and key='email';"`
1114 [ -n "$em" ] && echo "$em" || echo "$e"
1115 else
1116 # sql="with recursive allmem as
1117 # (select gname,val from grp_m where gname='$1'
1118 # union all select grp_m.gname,grp_m.val from grp_m,allmem
1119 # where allmem.val=grp_m.gname)
1120 # select coalesce(b.val,a.val)
1121 # from allmem a left join grp_mem_s b
1122 # on a.gname=b.gname and a.val=b.user and b.key='email'
1123 # where a.val in (select name from user) limit 10000;"
1124 # tmp tmp tmp tmp tmp tmp tmp
1125 qgrp=`sqlquote "$e"`
1126 sql="select coalesce(s.val,um.val,g.user) from
1127 grp_mem g left join grp_mem_s s
1128 on g.gname=s.gname and g.user=s.user and s.key='email'
1129 left join user_m um on g.user=um.name and um.key='email'
1130 where g.gname=$qgrp;"
1131 err CollectEmail: `echo "$sql"`
1132 query "$sql"
1133 fi
1134 done
1136 sendinvitation() (
1137 # $1=email
1138 iss="invite-`date +%s`-$user"
1139 addsession $iss +${memoplimitdays}days # 1 week due date
1140 query "replace into par values('$iss', 'invite', 'string', \"$1\");"
1141 gecos=`gecos`
1142 name=$user"${gecos:+($gecos)}"
1143 regist="$urlbase?reg+$iss"
1144 m4 -D_URL_="$urlbase" \
1145 -D_USER_="$name" \
1146 -D_EMAIL_="$1" \
1147 -D_REGIST_="$regist" \
1148 -D_ADMIN_="$admin" \
1149 $msgdir/mail-invite.m4 \
1150 | smail $1 "BBSへの御招待"
1151 return 0
1153 emaildomaincheck() {
1154 case "$1" in
1155 *@*@*) echo "無効なアドレスです"; return 1 ;;
1156 *@*)
1157 local=${1%@*} domain=${1#*@}
1158 if ! host $domain >/dev/null 2>&1; then
1159 echo "ドメイン($domain)が見付かりません。"
1160 return 2
1161 fi
1162 return 0
1163 ;;
1164 *) echo "正しいメイルアドレスをいれてください"; return 3 ;;
1165 esac
1167 invite() {
1168 email=`getpar email`
1169 case $email in
1170 *@*@*) repo="無効なアドレスです" ;;
1171 *@*)
1172 local=${email%@*} domain=${email#*@}
1173 if ! repo=`emaildomaincheck $email`; then
1174 repo="招待アドレスのエラー: $repo"
1175 elif [ -n "`query \"select * from user where name='$email';\"`" ]; then
1176 repo="$email さんは既に加入しています。"
1177 elif sendinvitation $email; then
1178 repo="アドレス($email)宛に案内を送信しました。"
1179 fi ;;
1180 "") repo="招待したい人のメイルアドレスを入力してください。" ;;
1181 *) repo="無効なアドレスです" ;;
1182 esac
1183 addr=`query "select val from par where sessid like 'invite-%-$user';"`
1184 err addr=$addr
1185 if [ -n "$addr" ]; then
1186 susp="<h2>招待済みで加入待ちのアドレス</h2><pre>$addr</pre>"
1187 fi
1188 m4 -D_TITLE_="招待" -D_REPORT_="\`$repo'" -D_ACTION_="?invite" \
1189 -D_BODYCLASS_="default" -D_SUSPENDED_="$susp" \
1190 $layout/html.m4.html $layout/invite.m4.html
1192 regist() {
1193 # $1=session-id-for-invitation
1194 m4 -D_TITLE_="Invitation" $layout/html.m4.html
1195 if [ -z "$1" ]; then
1196 echo "bye bye" | html p
1197 reutrn
1198 fi
1199 email=`session=$1 getpar invite`
1200 if [ -z "$email" ];then
1201 cat<<EOF
1202 <p>無効な招待状チケットです。</p>
1203 <p>招待状の有効期限(1週間)が切れているか、チケット番号が異なっています。
1204 加入している人に、再度招待してもらいましょう。</p>
1205 EOF
1206 return
1207 fi
1208 echo "$email さんようこそ" | html h2
1209 query "replace into user values('$email');"
1210 # Fake login password to wasureta
1211 query "replace into par values('$session', 'pswd', 'string', 'wasureta'),
1212 ('$session', 'user', 'string', '$email');"
1213 wasureta $email
1214 echo "このアドレスに初期パスワードを送信しました。" |html p
1215 echo "新着メイルを確認してログインしてください。" |html p
1216 addsession $1 # for removal after 1 minute
1217 m4 -D_SYSNAME_="Initial Login" -D_MYNAME_="$myname?userconf" \
1218 $layout/login.m4.html
1219 return
1221 newgrpchk() {
1222 # Check if $1 is existing and
1224 groupupdate() {
1225 gname=`getpar gname`
1226 qgname=`sqlquote $gname`
1227 err Enter:groupupdate
1228 if [ -n "$gname" ]; then
1229 # See ALSO same job in showgroup()
1230 newgname=`echo "$gname"|tr -d '\"'"'"`
1231 err newgname=$newgname
1232 if [ x"$newgname" != x"$gname" ]; then
1233 err NewGNAME: gname=$newgname
1234 gname=$newgname
1235 echo "使用禁止文字を除去し $gname としました。" | html p
1236 replpar gname string "$gname"
1237 fi
1238 # Name confliction check
1239 parow=`getpar rowid`
1240 err parow=$parow
1241 qgname=`sqlquote $gname` # Set again in case gname modified
1242 query "BEGIN EXCLUSIVE;"
1243 err "select count(gname) from grp where rowid != ${parow:-0} and gname = $qgname;"
1244 count=$(query "select count(gname) from grp where rowid != ${parow:-0} and gname = $qgname;")
1245 if [ $count -gt 0 ]; then
1246 echo "そのグループ名は既にあります。" | html p
1247 query "END;"
1248 return
1249 fi
1250 par2table $formdir/grp.def
1251 query "END TRANSACTION;"
1252 # Remove orphant
1253 : <<EOF
1254 select a.id,b.val from (select * from blog where id in
1255 (select id from blog_s where key='owner'
1256 and val not in (select name from user union select gname from grp)))
1257 a left join blog_s b on a.id=b.id and b.key='owner';
1258 EOF
1259 rm=`getpar rm` cfm=`getpar confirm`
1260 err groupupdate:::: after par2tbl rmcfm=$rm$cfm
1261 if [ x"$rm$cfm" = x"yesyes" ]; then
1262 if [ -z "`query \"select gname from grp where gname=$qgname;\"`" ]; then
1263 sql="delete from blog where id in
1264 (select id from blog_s where key='owner' and val=$qgname);"
1265 err rm-grp cleaning sql=`echo $sql`
1266 query "$sql";
1267 fi
1268 fi
1269 [ -z "$parow" ] && joingrp "$gname" "$user" yes "$user" as-admin
1270 fi
1271 sql="select rowid from grp where gname=$qgname;"
1272 grid=$(query $sql)
1273 err grpupdate:new-grid=$grid, sql=$sql
1274 grp $grid
1276 groupman() {
1277 note="<p>グループ名に使用できない文字は自動的に削除されます。</p>"
1279 GF_STAGE="grpconf"
1280 GF_STAGE=groupupdate
1281 DT_VIEW=grp dumptable html grp 'gname gecos:DESC mtime:TIME' 'order by b.TIME desc' \
1282 |m4 -D_TITLE_="グループ作成" \
1283 -D_FORM_="$note`genform $formdir/grp.def`" \
1284 -D_DUMPTABLE_="syscmd(cat)" \
1285 $layout/html.m4.html $layout/form+dump.m4.html
1287 userconf() {
1288 [ -n "`getpar rowid`" ] && par2table $formdir/user.def
1289 m4 -D_BODYCLASS_=userconf -D_TITLE_="ユーザ情報編集" $layout/html.m4.html
1290 GF_ACTION="?home" edittable "$formdir/user.def" "user" "$user"
1292 groupconf() {
1293 # $1=rowid in grp (2015-07-21 changed from gname)
1294 [ -n "`getpar rowid`" ] && par2table $formdir/grp.def
1295 m4 -D_BODYCLASS_=groupconf -D_TITLE_="グループ情報編集" $layout/html.m4.html
1296 #rowid=`query "select rowid from grp where gname='$1';"`
1297 rowid=${1%%[!A-Z0-9a-z_]*}
1298 err gcon \$1=$1 rowid=$rowid
1299 # GF_ACTION="?grp+$1" edittable "$formdir/grp.def" "grp" "$rowid" #2015-0804
1300 GF_STAGE="groupupdate" edittable "$formdir/grp.def" "grp" "$rowid"
1302 mems() {
1303 m4 -D_TITLE_="参加者一覧" -D_BODYCLASS_=listmember $layout/html.m4.html
1304 kwd=`getpar kwd`
1305 listmember $kwd
1307 grps() {
1308 m4 -D_TITLE_="グループ一覧" -D_BODYCLASS_=listgroup $layout/html.m4.html
1309 kwd=`getpar kwd`
1310 listgroup $kwd \
1311 | m4 -D_DUMPTABLE_="syscmd(cat)" \
1312 -D_TITLE_="グループ関連操作" \
1313 -D_FORM_="<a href=\"?groupman\">新規グループ作成</a>" \
1314 $layout/form+dump.m4.html
1316 grp() { # $1=group-rowid
1317 gpg=`getpar grp`
1318 grid=${1:-$gpg}
1319 grp=`getgroupbyid "$grid"`
1320 err grp: getpar-grp"(gpg)=[$grp]"
1321 ## . ./s4-blog.sh
1322 jg=`getpar joingrp`
1323 if [ -n "$jg" ]; then
1324 err jg=$jg, grp=$grp
1325 [ -n "$jg" -a -n "$grp" ] &&
1326 joingrp "$grp" "$user" "$jg" "`getpar email`"
1327 fi
1328 echo "グループ $grp"|m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1329 showgroup "$grid"
1331 showhome() {
1332 # $1=userRowIdToShow
1333 err showhome \$1=$1
1334 case "$1" in
1335 *@*) uname=`getvalbypkey user name "$1"` ;;
1336 *) uname=`getvalbyid user name $1` ;;
1337 esac
1338 err ShowHome: uname=$uname
1339 gecos=`gecos "$uname"`
1340 err SH:gecos=$gecos
1341 GF_VIEWONLY=1
1342 cond="gname in (select gname from grp_mem where user='$uname')"
1343 if [ x"$user" = x"$uname" ]; then
1344 conflink="<a href=\"?userconf\">プロフィールの編集</a> /
1345 <a href=\"?blog\">新規話題の作成</a>"
1346 # Display folders
1347 sql="select count(id) from article_m where id
1348 in (select id from article where author='$user')
1349 and type like 'file:%';"
1350 err nfile-sql=`echo "$sql"`
1351 nfile=`query "$sql"`
1352 err nfile=$nfile
1353 if [ $nfile -gt 0 ]; then
1354 conflink="$conflink /
1355 <a href=\"?lsmyfile\">過去の提出ファイル</a>"
1356 fi
1357 fi
1358 . ./s4-blog.sh
1360 tf=$tmpd/title.$$ pf=$tmpd/profile.$$ bf=$tmpd/blogs.$$
1361 echo "$gecos さん" > $tf
1362 viewtable $formdir/user.def user $1 > $pf
1363 listblog $uname > $bf
1364 listgroupbytable $formdir/grp.def $cond \
1365 | m4 -D_BODYCLASS_=home -D_TITLE_="spaste(\`$tf')" \
1366 -D_PROFILE_="spaste(\`$pf')$conflink" \
1367 -D_BLOGS_="spaste(\`$bf')" \
1368 -D_GROUPS_="syscmd(\`cat')" \
1369 $layout/html.m4.html $layout/home.m4.html
1371 if [ x"$user" = x"$uname" ]; then
1372 # Display NEWS
1373 cond="where 新着 > 0 order by 新着 desc,ctime desc limit 10"
1374 new10=`DT_CHLD=article:blogid \
1375 DT_VIEW=replyblog dumptable html blog "ctime title gecos" "$cond"`
1376 cont=`echo "$new10"|grep "^<TR>"|wc -l`
1377 cont=$((cont-1))
1378 err newcount=$cont
1379 if [ $cont -gt 0 ]; then
1380 echo "全体の新着記事${cont}傑" | html h2
1381 echo "$new10"
1382 fi
1383 cat<<EOF
1384 <div class="fold">
1385 `cgi_checkbox srchall yes id="sa"`<label
1386 for="sa">SNS全体から検索</label>
1387 <div>
1388 EOF
1389 cgi_form searchart<<EOF
1390 <label>`cgi_text kwd`という語を含む記事を全部から検索</label>
1391 EOF
1392 cat<<EOF
1393 </div></div>
1394 EOF
1395 fi
1397 # Record access log
1398 [ -n "$1" ] && [ x"$1" != x"$user" ] && acclog user $1
1400 commission() { # $1=grp-rowid $2=user-rowid
1401 contenttype; echo
1402 err commission: "$@"
1403 gname=`getgroupbyid $1`
1404 echo "グループ $gname 管理者委任" \
1405 | m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1406 if [ -n "$2" ]; then
1407 grp_reg_adm "$@"
1408 else
1409 echo "無効な指定です。普通のアクセスならここに来ないはず。"|html p
1410 fi
1412 listgroupbytable() {
1413 # $1=deffile $2...=condition
1414 tagline=`grep :tag: $1`; shift
1415 and="${1:+and }" where=${1:+where }
1416 href="<a href=\"$myname?grp+"
1417 echo '<div class="listgroup">'
1418 NGsql="select distinct tag from\
1419 (select gname, max(case key when 'tag' then val end) as tag, \
1420 max(case key when 'ctime' then val end) as ctime\
1421 from grp_s group by gname order by ctime);"
1422 sql="select val from grp_s where key='tag' $and$* group by val;"
1423 err ListGRP: query sql="$sql"
1424 for tag in `query "$sql"`
1425 do
1426 err ListGrp: tag=$tag
1427 tn=${tagline%%=${tag}*}
1428 tn=${tn##*[ :]}
1429 sql="select rowid||':'||gname as 'グループ名',説明 from
1430 (select (select rowid from grp g where g.gname=grp_s.gname)
1431 as rowid,
1432 gname,
1433 max(case key when 'gecos' then val end) as '説明',
1434 max(case key when 'tag' then val end) as 'tag',
1435 max(case key when 'mtime' then val end) as mtime from grp_s
1436 $where$* group by gname having tag='$tag' order by mtime desc);"
1437 err PersonalGroupList= `echo $sql`
1438 echo "<h2>$tn</h2>"
1439 echo '<table class="b listgroup">'
1440 sq -header -html $db "$sql" \
1441 | sed "s,\(<TR><TD>\)\([0-9]*\):\([^ ]*\)</TD>,\1$href\2\">\3</a>,"
1442 echo '</table>'
1443 done
1444 echo '</div>'
1446 iconhref() (
1447 # $1=icon-file, $2=Href $3=title $4...=anchor
1448 data=`percenthex $1`
1449 ct=`file --mime-type $1|cut -d' ' -f2`
1450 err iconhref: \$1=$1 \$2=$2 \$3="$@"
1451 href=$2; title=$3; shift 3
1452 echo "<a href=\"$href\"><img title=\"$title\" src=\"data:$ct,$data\">$@</a>"
1454 iconhref2() (
1455 # $1=icon-file, $2=Href $3=title $4...=anchor
1456 src=$1
1457 href=$2; title=$3; shift 3
1458 echo "<a href=\"$href\"><img title=\"$title\" src=\"$src\">$@</a>"
1460 listentry() (
1461 # $1=user/group $2=SearchKeyword $3=condition(if any)
1462 # Referring variable $iamowner=$grp to attach owner-request links
1463 err listentry: \$1=$1 \$2=$2 \$3=$3
1464 cond=''
1465 offset=`getpar offset`
1466 offset=${offset%%[!0-9]*}
1467 offset=$((offset + 0)) # change to numeric forcibly
1468 [ $offset -lt 0 ] && offset=0
1469 limit=30
1470 dir=`getcachedir "$1"`
1471 if [ x"$1" = x"user" ]; then
1472 hrb="$myname?home"
1473 deficon=person-default.png
1474 entity="ユーザ" tbl=user link=rowid nm=name stage=mems
1475 gcs=gecos
1476 else # if group
1477 hrb="$myname?grp"
1478 deficon=group-default.png
1479 entity="グループ" tbl=grp link=rowid nm=gname stage=grps
1480 gcs=name
1481 tagline=`grep :tag: $formdir/grp.def|cut -d: -f5-`
1482 if [ -n "$tagline" ]; then
1483 tagconv=`echo $tagline|sed 's/\([^= :]*\)=\([^= :]*\)/-D\2=\1/g'`
1484 err tagconv=$tagconv
1485 fi
1486 fi
1487 if [ ! -d $dir ]; then
1488 mkdir -p $dir
1489 fi
1490 if [ ! -s $dir/$deficon ]; then
1491 convert -geometry $thumbxy $imgdir/$deficon $dir/$deficon
1492 fi
1493 if [ -n "$2" ]; then
1494 cond="where nick like '%$2%' or b.name like '%$2%'"
1495 fi
1497 # XX: これ複雑すぎるかな。もっとシンプルにしたい。$3条件も。2015-07-08
1498 # grpは呼出し元の動的スコープ変数でよくないな...
1499 ##qgrp=`sqlquote $grp`
1500 getgrp="(select gname from grp where rowid=${rowid:--1})"
1501 sql="select a.rowid, a.$link, coalesce(b.$gcs, a.$nm) as nick,
1502 coalesce(b.gecos, a.$nm) as name,
1503 b.tag,
1504 case when a.$nm in (select user from grp_adm
1505 where gname=$getgrp) then '(管理者)'
1506 when '$user' in (select user from grp_adm where gname=a.$nm)
1507 then '(ADMIN)'
1508 when '$iamowner' = '' then ''
1509 else ',not='||a.rowid end as ownerlink
1510 from $tbl a left join
1511 (select $nm as name,
1512 max(case key when 'gecos' then val end) as gecos,
1513 max(case key when 'tag' then val end) as tag
1514 from ${tbl}_s group by $nm)
1515 b on a.$nm=b.name $cond $3
1516 order by b.tag desc, a.rowid asc"
1517 err LE:sql.1="$sql"
1518 total=`query "with x as ($sql) select count(*) from x;"`
1519 echo "${entity} 一覧" | html h2
1520 if [ $total -gt $limit ]; then
1521 echo '<div class="right">'
1522 cgi_form $stage <<EOF
1523 <label>次の語を含む${entity}で検索:
1524 `cgi_text kwd $kwd`</label>
1525 EOF
1526 echo '</div>'
1527 fi
1528 cat<<EOF
1529 <p>${total}件中の$((offset+1))件めから${kwd:+" - 検索語: $kwd"}</p>
1530 EOF
1531 if [ $((offset+limit)) -lt $total ]; then
1532 cat<<EOF
1533 <div class="right"><form action="$myname" method="POST">
1534 `cgi_submit 次の${limit}件`
1535 `cgi_hidden kwd "$kwd"`
1536 `cgi_hidden stage "$stage"`
1537 `cgi_hidden offset $((offset + limit))`</form></div>
1538 EOF
1539 fi
1540 if [ $offset -gt 0 ]; then
1541 cat<<EOF
1542 <form action="$myname" method="POST">
1543 `cgi_submit 前の${limit}件`
1544 `cgi_hidden stage "$stage"`
1545 `cgi_hidden kwd "$kwd"`
1546 `cgi_hidden offset $((offset - limit))`</form>
1547 EOF
1548 fi
1550 err ListEntry: `echo "$sql"\;`
1552 query "$sql limit $limit ${offset:+offset $offset};" \
1553 | while IFS='|' read id lnk name gecos tag ownerp; do
1554 err name=$name owner=$ownerp lnk=$lnk
1555 err newlnk=$lnk
1556 files=`getvalbyid $tbl profimg $id $dir`
1557 # Pick up only first icon
1558 echo "<div class=\"iconlist xy$thumbxy\"><p class=\"tag _$tag\">$tag</p>" \
1559 | m4 $tagconv
1560 if [ -n "$files" ]; then
1561 icon=`echo "$files"|head -1`
1562 iconhref $dir/$icon "$hrb+$lnk" "$gecos"
1563 else
1564 iconhref $dir/$deficon "$hrb+$lnk" "$gecos"
1565 fi
1566 echo "<br>$name${ownerp:+<br>$ownerp}"
1567 echo "</div>"
1568 done
1570 listmember() {
1571 listentry user "$@"
1573 listgroup() {
1574 listentry group "$@"
1576 showgroup() { # $1=group-rowid
1577 # gname=`getpar gname`
1578 # if [ -n "$gname" ]; then
1579 # err UPdating/Removing of group:::::::
1580 # # See ALSO same job in groupman()
1581 # newgname=`echo "$gname"|tr -d '\"'"'"`
1582 # ###newgname=$gname
1583 # err gname=$gname newgname=$newgname
1584 # if [ x"$newgname" != x"$gname" ]; then
1585 # err NewGNAME: gname=$newgname
1586 # gname=$newgname
1587 # echo "使用禁止文字を除去し $gname としました。" | html p
1588 # replpar gname string "$gname"
1589 # fi
1590 # par2table $formdir/grp.def
1591 # fi
1592 grp=`getgroupbyid $1`
1593 err showgroup2: grp=$grp qgrp="[$(sqlquote $grp)]"
1594 if isgroup "$grp"; then
1595 tf=$tmpd/title.$$
1596 echo "グループ $grp" > $tf
1597 showgroupsub $formdir/grp.def "$1" | \
1598 m4 -D_TITLE_="spaste(\`$tf')" \
1599 -D_FORM_="syscmd(\`cat')" \
1600 -D_DUMPTABLE_="" \
1601 $layout/form+dump.m4.html
1602 else # if $grp is removed at par2table
1603 listgroup
1604 fi
1606 showgroupsub() {
1607 # $1=def-file $2=group-rowid
1608 rowid=$2
1609 grp=`getgroupbyid $2`
1610 qgrp=`sqlquote $grp`
1611 #rowid=`sq $db "select rowid from grp where gname=$qgrp"`
1612 if [ -z "$rowid" ]; then
1613 #rowid=`sq $db "select rowid from grp where rowid=$grp"`
1614 #grp=`sq $db "select gname from grp where rowid=$grp"`
1615 echo "showgroupsub: invalid argument($1 $2)" | html p
1616 return
1617 fi
1618 val=`getvalbyid grp profimg $rowid $tmpd`
1619 # 6/14の次グループのHOMEで出す情報を作る Done
1620 viewtable $1 grp $rowid
1621 if isgrpowner "$user" "$grp"; then
1622 echo "<p><a href=\"?groupconf+$rowid\">グループ情報の編集</a>"
1623 iamowner=$rowid
1624 fi
1625 if ismember "$user" "$grp"; then
1626 echo "${iamowner:+ / }<a href=\"?blog+$rowid\">グループの新規話題作成</a>"
1627 echo "/ <a href=\"?grpaction+$rowid\">メンバーを個別選択しての操作</a></p>"
1628 # div.fold input[type="checkbox"]:checked ~ div {display: block;}
1629 cat<<EOF
1630 <form action="?send2mem" method="POST" enctype="multipart/form-data">
1631 <div class="fold">
1632 `cgi_checkbox send yes id="send"`<label
1633 for="send">グループ全員にメッセージ送信</label>
1634 <div>
1635 `cgi_textarea message "" "cols=60"`
1636 `cgi_submit 送信`
1637 `cgi_reset リセット`
1638 </div>
1639 `cgi_hidden grp $rowid`
1640 </div></form>
1641 EOF
1642 fi
1643 # 加入ボタン + 加入者リスト
1644 err ismember $user $grp
1645 ismember "$user" "$grp" && ismem='checked' || nomem='checked'
1646 # このグループでの加入アドレス
1647 eml=`query "select val from grp_mem_s where gname='$2' and user='$user' \
1648 and key='email';"`
1649 err EML: "select val from grp_mem_s where gname='$2' and user='$user' \
1650 and key='email';"
1651 err email=$eml
1652 cat <<EOF
1653 <div class="fold">
1654 `cgi_checkbox reg yes id="reg"`<label
1655 for="reg">自身の参加状態を操作する</label>
1656 <div>
1657 EOF
1658 cgi_form grp <<EOF
1659 <p>このグループに</p>
1660 <table class="b">
1661 <tr><th>メンバーとして</th><td>
1662 <label>`cgi_radio joingrp "yes" $ismem`参加</label> /
1663 <label>`cgi_radio joingrp "no" $nomem`参加しない</label></td></tr>
1664 <tr><th>参加する場合のメイルアドレス<br>
1665 <small>(メインのアドレスとは違うものにする場合に記入<br>
1666 同じでよい場合は空欄に)</small></th>
1667 <td>`cgi_text email $eml`</td></tr>
1668 </table>
1669 `cgi_hidden grp $rowid`
1670 EOF
1671 if [ x`getgroupattr $grp regmode` = x'moderated' -a -z "$ismem" ]; then
1672 echo "moderated (承認加入の)グループなので実際に参加できるのは
1673 グループ管理者が承認操作をした後になります。" | html p 'class="warn"'
1674 fi
1675 echo '</div></div>'
1676 echo '<h2>話題一覧</h2>'
1677 cgi_form searchart<<EOF
1678 <label>`cgi_text kwd`という語を含むコメントを検索</label>
1679 `cgi_hidden owner $grp`
1680 EOF
1681 cond="where a.id in (select id from blog_s where key='owner' and val=$qgrp) order by ctime desc"
1682 DT_CHLD=article:blogid \
1683 DT_VIEW=replyblog dumptable html blog 'ctime title heading' "$cond"
1685 getgname="(select gname from grp where rowid=$rowid)"
1686 c="group by b.name having b.name in (select user from grp_mem where gname=$getgname)"
1687 cm="?commission+$rowid"
1688 thumbxy=50x50 listmember "" "$c" \
1689 |sed -e "s|\(<br>\),not=\(.*\)|\1<a href=\"$cm+\2\">管理者委託</a>|"
1691 grpaction() { # $1=group-rowid
1692 err GRP_ACTION:IN
1693 grid=${1:-`getpar grp`}
1694 grp=`getgroupbyid "$grid"`
1695 if [ -z "$grp" ]; then
1696 echo "無効な指定です。" | html p; return
1697 fi
1698 if ! ismember $user $grp; then
1699 echo "加入者のみに許可された操作です。" | html p; return
1700 fi
1701 echo "グループ $grp 個別選択操作" \
1702 | m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1704 isowner=""
1705 isgrpowner "$user" "$grp" && isowner="yes"
1706 usel=`getpar usel`
1707 if [ -n "$usel" ]; then
1708 uids=$(echo `echo $usel`|tr ' ' ',')
1709 err grpaction-1: grp=$grp, `echo $sql`
1710 text=`getpar text`
1712 rm=`getpar rm` cfm=`getpar confirm`
1713 err rm=$rm cfm=$cfm
1714 if [ x"$rm" = x"yes" ]; then
1715 if [ "$isowner" ]; then
1716 if [ x"$rm$cfm" = x"yesyes" ]; then
1717 # Eliminate
1718 cond="where gname=(select gname from grp where rowid=$grid) and user in (select name from user where rowid in ($uids))"
1719 for tbl in grp_mem grp_mem_s grp_mem_m; do
1720 sql="delete from $tbl $cond;"
1721 # echo "sql=$sql"
1722 query "$sql"
1723 err rmGRPuser "$sql"
1724 done
1725 num=`query "select count(*) from user where rowid in ($uids);"`
1726 #err num=$num
1727 if [ 0$num -gt 0 ]; then
1728 sql="select coalesce(b.val,a.name) from user a left join \
1729 user_s b on a.name=b.name and key='gecos' where a.rowid in ($uids);"
1730 # err `echo "$sql"`
1731 html pre<<EOF
1732 以下の${num}名のグループ $grp 登録を解除しました。
1733 `query "$sql"`
1734 EOF
1735 fi
1736 else
1737 echo "確認のチェックがないのでやめておきます。" | html p
1738 return
1739 fi
1740 else # not Group Owner
1741 echo "グループ管理者でないのでメンバー操作はできません。" | html p
1742 return
1743 fi
1744 cat<<EOF
1746 EOF
1747 elif [ -n "$text" ]; then # if NOT removal mode
1748 smail "`email4groupbyuid "$grp" $usel` $user" \
1749 "`gecos $user` さんからのメッセージ" <<EOF
1750 $url
1751 のグループ「$grp」のメンバーである `gecos $user` さんから、
1752 あなた宛へのメッセージです。
1753 ----------------------------------------------------------
1754 $text
1755 EOF
1756 if [ $? = 0 ]; then
1757 echo "Note: 以下のメンバーにメッセージを送信しました。" | html p
1758 sql="select coalesce(b.val, a.name) from
1759 (select name from user where rowid in ($uids)) a
1760 left join user_s b on a.name=b.name and b.key='gecos';"
1761 html pre<<EOF
1762 `query "$sql"`
1763 (送信者である `gecos $user` さんも含まれます)
1764 EOF
1765 err SendDone: `echo $sql`
1766 fi
1767 fi
1768 fi
1769 # New entry
1770 sql="select u.rowid||','||j.* from user u
1771 join (select a.user as name,coalesce(b.val,a.user)
1772 from (select gname,user from grp_mem
1773 where gname=(select gname from grp where rowid=$1))
1774 a left join (select gname,user,val from grp_mem_s where key='email')
1775 b using(gname,user))
1776 j using(name) order by u.name;"
1777 sql="select a.rowid||','||coalesce(val,a.name) as name from
1778 (select rowid,name from user where name in
1779 (select user from grp_mem where
1780 gname=(select gname from grp where rowid=$grid)))
1781 a left join user_s on a.name=user_s.name and key='gecos'
1782 order by name;"
1783 err grpaction: `echo $sql`
1784 b1='<label> <input type="checkbox" name="usel" value="'
1785 b2='"> ' b3='</label>'
1786 tf=$tmpd/title.$$
1787 echo "グループ[$grp]参加メンバーに対する操作" > $tf
1788 excmsg="<div class=\"fold\">
1789 `cgi_radio rm yes ` 下でチェックした人のグループ登録解除
1790 <div>
1791 本当に消します! `cgi_checkbox confirm yes` 確認
1792 <p>この操作による通知は本人に行きません。
1793 あらかじめ通知するか、登録解除してよい状況かしっかり確認してください。</p>
1794 </div>
1795 </div>"
1796 cgi_form grpaction<<EOF \
1797 | sed -e "s|^\(<TR><TD>\)\([0-9]*\),\([^<]*\)|\1$b1\2$b2\3$b3|" \
1798 | m4 -D_TITLE_="spaste(\`$tf')" \
1799 -D_SUBTITLE_="チェック後操作ボタン" \
1800 -D_FORM_="syscmd(cat)" -D_DUMPTABLE_="" \
1801 $layout/form+dump.m4.html
1802 <div class="fold">
1803 `cgi_radio rm send id="sendmsg"`<label
1804 for="sendmsg">下でチェックした人にメッセージを送信する</label>
1805 <div>
1806 `cgi_textarea text "" cols=40`
1807 </div>
1808 </div>
1809 ${isowner:+$excmsg}
1810 <h4>$grp 参加者一覧</h4>
1811 <table>
1812 `sq $db -html "$sql"`
1813 `cgi_hidden grp $grid`
1814 </table>
1815 EOF
1817 editheading() { # $1=rowid-of-heading
1818 rowid=${1%%[!A-Z0-9a-z_]*}
1819 if [ -z "$rowid" ]; then
1820 echo "話題番号が未指定です。" | html p
1821 return
1822 fi
1823 owner=`getvalbyid blog owner $rowid`
1824 title=`getvalbyid blog title $rowid`
1825 GF_ACTION="?blog" edittable $formdir/blog.def blog $rowid \
1826 | m4 -D_TITLE_="修正" \
1827 -D_SUBTITLE_="[$title]@$owner" -D_DIARY_="" \
1828 -D_BLOGS_="" -D_DUMPTABLE_="" \
1829 -D_FORM_="syscmd(\`cat')" \
1830 $layout/html.m4.html $layout/form+dump.m4.html
1832 editart() { # $1=article-rowid $2=blogrowid
1833 rowid=${1%%[!A-Z0-9a-z_]*}
1834 blogrowid=${2%%[!A-Z0-9a-z_]*}
1835 if [ -z "$rowid" -o -z "$blogrowid" ]; then
1836 echo "表示する記事番号が未指定です。" | html p
1837 return
1838 fi
1839 owner=`getvalbyid blog owner $blogrowid`
1840 title=`getvalbyid blog title $blogrowid`
1841 author=`getvalbyid article author $rowid`
1842 err EDITart: owner=$owner, author=$author
1843 if isgrpowner $user $owner; then
1844 : EDIT OK
1845 elif [ x"$owner" != x"$user" -a x"$author" != x"$user" ]; then
1846 echo "本人か所有者しか編集できません." | html p
1847 return
1848 fi
1849 aid=`query "select id from article where rowid=$rowid;"`
1850 tmpout=$tmpd/editart.$$.out
1851 GF_ACTION="?replyblog+$blogrowid#$aid" \
1852 edittable $formdir/article.def article $rowid \
1853 > $tmpout
1854 rm -f /tmp/editart.out
1855 # Cannot use pipelining to m4 with genform() because of stdin stack
1856 m4 -D_TITLE_="コメントの修正" -D_DIARY_="" \
1857 -D_FORM_="syscmd(cat $tmpout)" \
1858 -D_SUBTITLE_="`gecos $owner`の「$title」" \
1859 -D_BLOGS_= -D_DUMPTABLE_= \
1860 $layout/html.m4.html $layout/form+dump.m4.html
1862 send2mem() {
1863 rowid=`getpar grp`
1864 if [ -z "$rowid" ]; then
1865 echo "グループが未指定です。" | html p
1866 return
1867 fi
1868 message=`getpar message`
1869 if [ -z "$message" ]; then
1870 echo "文章を入れてください。" | html p
1871 return
1872 fi
1873 grp=`getgroupbyid $rowid`
1874 members=`collectemail $grp`
1875 # smail rcpt subj (file)
1876 smail "$members" "グループ $grp 宛メッセージ(from `gecos $user`)" <<EOF
1877 $urlbase?grp+$rowid
1878 グループ $grp に所属する
1879 `gecos $user` さんよりメッセージ:
1881 $message
1882 EOF
1883 cat<<EOF
1884 <p>以下の宛先に送信しました。</p>
1885 <pre>
1886 $members
1887 </pre>
1888 <p><a href="?grp+$rowid">グループ $grp</a>に戻る。</p>
1889 EOF
1891 joingrpadmit() {
1892 # $1=yes/no $2=session-key
1893 if [ -z "$2" ]; then
1894 echo "bye bye" | html p; return
1895 fi
1896 t_usr=`session=$2 getpar user`
1897 t_grp=`session=$2 getpar group`
1898 err joingrpadmit: t_usr=$t_usr, t_grp=$t_grp
1899 m4 -D_TITLE_="joingrp" $layout/html.m4.html
1900 if [ -z "$t_usr" -o -z "$t_grp" ]; then
1901 echo "無効な加入依頼です。" | html p
1902 echo "有効期限が切れたか、
1903 他の管理者がいる場合は処理済みの可能性があります。" | html p
1904 return
1905 fi
1906 if ! isgrpowner "$user" $t_grp; then
1907 echo "グループ管理者のみの機能です。" | html p; return
1908 fi
1909 case $1 in
1910 yes) joingrp "$t_grp" "$t_usr" yes "$t_usr" ;;
1911 no) joingrp "$t_grp" "$t_usr" no "$t_usr" ;;
1912 *)
1913 echo "無効な指定です($1)。" | html p
1914 return ;;
1915 esac
1916 gid=$(query "select rowid from grp where gname=`sqlquote $t_grp`;")
1917 rcpts="`getgroupadminmails $t_grp` $user"
1918 err admit: msgdir=$msgdir, rcpts="["$rcpts"]"
1919 body="グループ $t_grp
1920
1921 $t_usr
1922 `[ x$1 = xyes ] && echo 'を追加' || echo 'の解除操作を'`
1923 しました。"
1924 (echo "$body"; echo; echo "$url?grp+$gid") | smail "$rcpts" "joingrp $1"
1925 query "delete from session where id='$2';"
1926 echo "$body" | html p
1929 joingrprequest() {
1930 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
1931 jss="joingrp-`date +%s`-`genrandom 12`"
1932 addsession $jss +${memoplimitdays}days
1933 query "replace into par values('$jss', 'group', 'string', `sqlquote $1`),
1934 ('$jss', 'user', 'string', `sqlquote $user`);"
1935 smail "$(collectemail `getgroupadmins $1`)" "Join request to $1"<<EOF
1936 $url
1937 グループ $1
1938 に加入依頼がありました。
1940 承認する:
1941 $urlbase?joingrpadmit+yes+$jss
1943 白紙に戻す:
1944 $urlbase?joingrpadmit+no+$jss
1945 EOF
1946 echo "管理者に加入依頼を出しました。
1947 ${memoplimitdays}日以内に加入承認操作がされれば加入できますが、
1948 グループ運用方針に懸かることですので直接の問い合わせが重要です。" | html p
1950 joingrp() {
1951 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
1952 err joingrp: \$1=$1 \$2=$2 \$3=$3 \$4=$4
1953 isgrpowner "$user" "$1" && isowner="yes" || isowner=""
1954 err jg:isgrpowner: isowner="$isowner"
1955 if [ -n "$isowner" ]; then
1956 : # GROUP OWNER CAN DO EVERYTHING ABOUT REGISTRATION/RETIREMENT
1957 elif [ x"$2" != x"$user" ]; then # if user is not login user
1958 echo "本人か、グループ管理者しか加入操作はできません。" | html p
1959 return
1960 elif [ x"$3" = x"no" ]; then
1961 : # Do not pursue those who leave
1962 else # adding user is $user itself
1963 case `getgroupattr $1 regmode` in
1964 moderated)
1965 joingrprequest "$@" # Request only
1966 return
1967 ;;
1968 *)
1969 ;;
1970 esac
1971 fi
1972 qgname=`sqlquote $1`
1973 cond="where gname=$qgname and user='$2'"
1974 if [ x"$3" = x"yes" ]; then
1975 query "replace into grp_mem values($qgname, '$2');"
1976 if [ -n "$4" ]; then
1977 if msg=`emaildomaincheck "$4"`; then
1978 err "replace into grp_mem_s values($qgname, '$user', 'email', \
1979 'string', '$4', NULL);"
1980 query "replace into grp_mem_s values($qgname, '$user', 'email', \
1981 'string', '$4', NULL);"
1982 if [ -n "$5" ]; then # as ADMIN
1983 # Coming here means newly created group
1984 sql="select case\
1985 when (select count(*) from grp_mem where gname=$qgname)=1\
1986 then (select user from grp_mem\
1987 where gname=$qgname and user='$user')\
1988 else '' end;"
1989 err NewGrpChk: $sql
1990 if [ -n "`query \"$sql\"`" ]; then
1991 err ADMIN: "replace into grp_adm values($qgname, '$user');"
1992 query "replace into grp_adm values($qgname, '$user');"
1993 fi
1994 fi
1995 else
1996 echo $msg
1997 fi
1998 else
1999 query "delete from grp_mem_s $cond and key='email';"
2000 fi
2001 else
2002 query "delete from grp_mem $cond;
2003 delete from grp_mem_s $cond;
2004 delete from grp_mem_m $cond;"
2005 fi
2007 grp_reg_adm() {
2008 # $1=grp-rowid $2=user-rowid
2009 grp=`getgroupbyid "$1"`
2010 if [ -z "$grp" ]; then
2011 echo "無効なグループIDです" | html p; return
2012 fi
2013 if ! isgrpowner $user "$grp"; then
2014 echo "$grp グループの管理者しかこの操作はできません。" | html p; return
2015 fi
2016 newadm=`query "select name from user where rowid=$2;"`
2017 if [ -z "$newadm" ]; then
2018 echo "指定ユーザIDがおかしいようです。" | html p; return
2019 fi
2020 err GRP_reg_adm: "replace into grp_adm values(`sqlquote $grp`, '$newadm');"
2021 err ismember $newadm $grp
2022 if ismember $newadm $grp; then
2023 # OK, go ahead
2024 getgname="(select gname from grp where rowid=$1)"
2025 query "replace into grp_adm values($getgname, '$newadm');"
2026 # confirm insertion
2027 sql="select * from grp_adm where gname=$getgname and user='$newadm'"
2028 if [ -n "`query \"$sql;\"`" ]; then
2029 echo "追加完了" | html p
2030 else
2031 echo "追加失敗($1 $2)" | html p
2032 fi
2033 fi
2034 showgroup $1
2036 dumptable() {
2037 # $1=mode $2=Table $3=column-list-of-*_s(defaults to *) $4=conditions(if any)
2038 # textのフィールドだけ全てダンプにしたほうがいいか
2039 # $DT_VIEW sets link
2040 # 6/17の次: editリンクじゃなくてスレッドVIEWリンクでいいんちゃう?
2041 ### elink="<a href=\"$myname?edittable+$2+\\2\">EDIT</a>"
2042 VIEW=${DT_VIEW-replyblog}
2043 if [ -n "$VIEW" ]; then
2044 dvlink=" <a href=\"$myname?$VIEW+\\2\">VIE</a><a href=\"$myname?$VIEW+\\2#bottom\">W</a>"
2045 fi
2046 # $DT_CHLD=ChildTable:BindColumn
2047 if [ -n "$DT_CHLD" ]; then
2048 _t=${DT_CHLD%:*} _i=${DT_CHLD#*:}
2049 cntall="(select count($_i) from $_t where $_i=a.id)"
2050 cntnew="(select count(val) from ${_t}_s where key='ctime' \
2051 and id in (select id from $_t where $_i=a.id) \
2052 and val > coalesce((select time from acclog where \
2053 user='$user' and tbl='$2' and rowid=a.rowid),\
2054 '1970-01-01'))"
2055 cnt="$cntnew as '新着', $cntall as '総数',"
2056 dt_class=" td2r td3r"
2057 fi
2058 # Construct join expression
2059 eav="" scols=""
2060 pk=`gettblpkey $2`
2061 substr=${dumpcollen:+"substr(val, 0, $dumpcollen)"}
2062 substr=${substr:-val}
2063 for col in ${3:-`gettbl_s_cols $2`}; do
2064 case $col in
2065 gecos) scols="$scols${scols:+, }${col#}"
2066 continue ;; # built-in column name
2067 *:*) col=${col%:*} as=${col#*:} ;;
2068 *) as=${col} ;;
2069 esac
2070 eav=$eav${eav:+,}" max(case key when '$col' then $substr end) as $as"
2071 scols="$scols${scols:+, }b.$as"
2072 done
2073 #case author when '$user' then a.rowid else '---' end as ID,
2074 sql="select \
2075 a.rowid as ID,\
2076 $cnt\
2077 $scols from $2 a left join\
2078 (select $pk,$eav,
2079 max(case key when 'owner'
2080 then coalesce((select val from user_s us
2081 where us.key='gecos' and us.name=c.val), val) end) as gecos
2082 from ${2}_s c group by $pk) b on a.$pk=b.$pk $4;"
2083 err SQL=`echo "$sql"`
2084 cat<<EOF | sed "s,\(<TR><TD>\)\([1-9][0-9]*\)</TD>,\1$elink$dvlink</TD>,"
2085 <div class="dumptable">
2086 <table class="b$dt_class">
2087 `sq -header -cmd ".mode $1" $db "$sql"`
2088 </table>
2089 </div> <!-- dumptable -->
2090 EOF
2093 par2table() (
2094 # copy current parameters of par into destination table
2095 # $1=definition-file
2096 # Using $user and $session
2097 # Return value:
2098 # 0: Stored successfully
2099 # 1: Insufficient fillings
2100 # 2: No permission to modify the record
2101 # 3: Invalid rowid
2102 # 4: SUCCESS to delete
2103 # 5: Stop deletion for lack of confirm check
2104 # 6: Password length too short
2105 # 7: Password mismatch
2106 # 8: Old password incorrect
2107 rowid=`getpar rowid`
2108 err ...........rowid=$rowid
2109 if [ ! -e $1 ]; then
2110 echo "テーブル定義ファイルが見付かりません" | html p
2111 exit 1
2112 fi
2113 tbl=${1%.def}
2114 tbl=${tbl##*/}
2115 if [ -n "$rowid" ]; then # Modify existing entry
2116 if [ x"$tbl" = x"user" ]; then
2117 rowowner=`query "select name from $tbl where rowid=$rowid;"`
2118 elif [ x"$tbl" = x"grp" ]; then
2119 sql="select gname from $tbl where rowid=$rowid;"
2120 ##err p2t:grp:q $sql
2121 isgrpowner $user "`query $sql`" && rowowner=$user
2122 else
2123 rowowner=`query "select owner from $tbl where rowid=$rowid;"`
2124 rowowner=${rowowner:-`query "select author from $tbl
2125 where rowid=$rowid;"`}
2126 fi
2127 ### err rowowner=$rowowner
2128 if [ x"$user" != x"$rowowner" ]; then
2129 echo "他人のレコードはいじれないの" | html p
2130 return 2
2131 elif [ -z "$rowowner" ]; then
2132 echo "指定したレコードはないみたい" | html p
2133 return 3
2134 fi
2135 rm=`getpar rm` cfm=`getpar confirm`
2136 # Editing existent entry
2137 if [ x"$rm" = x"yes" ]; then
2138 if [ x"$rm$cfm" = x"yesyes" ]; then
2139 query "delete from $tbl where rowid=$rowid;"
2140 return 4
2141 else
2142 echo "消去確認のチェックがないので消さなかったの..." | html p
2143 return 5
2144 fi
2145 fi
2146 fi
2147 # XX: Subshelling here is unnecessary 2015-07-05
2148 (ts=${tbl}_s tm=${tbl}_m val="" pval="" formaster=""
2149 if [ -n "$rowid" ]; then
2150 # Update of existing record
2151 for col in `gettblcols $tbl`; do
2152 val=`getparquote $col`
2153 [ -z "$val" ] && continue
2154 err query "update $tbl set $col=$val where rowid=$rowid"
2155 query "update $tbl set $col=$val where rowid=$rowid;"
2156 done
2157 # Then, set up $pval for further insertion of tbl_s and tbl_m
2158 for col in `gettblpkey $tbl`; do
2159 val=`query "select $col from $tbl where rowid=$rowid;"|sed -e 's/\"/\"\"/g'`
2160 pval="$pval${pval:+, }\"$val\""
2161 done
2162 else
2163 # New entry
2164 # Generate values() for primary keys
2165 for col in `gettblpkey $tbl`; do
2166 # Genuine primary keys for _m and _s
2167 val=`getvalquote $tbl $col`
2168 [ -z "$val" ] && continue
2169 pval="$pval${pval:+, }$val"
2170 done
2171 err pval=$pval
2172 for col in `gettblfkey $tbl`; do
2173 # args for values() to insertion into master table
2174 val=`getvalquote $tbl $col`
2175 [ -z "$val" ] && continue
2176 formaster=$formaster"${formaster:+, }$val"
2177 done
2178 formaster="$pval${formaster:+, }$formaster"
2179 err formaster=$formaster
2180 if [ -z "$formaster" ]; then
2181 echo "項目を全て埋めてください" | html pre
2182 return 1
2183 fi
2184 err "replace into $tbl values($formaster);"
2185 query "replace into $tbl values($formaster);"
2186 ## Insertion to master table, done
2187 fi
2189 for kt in s m; do
2190 tb2=${tbl}_$kt
2191 for col in `gettbl_${kt}_cols $tbl`; do
2192 ptype=`getpartype $col "limit 1"`
2194 # First, check update of existing entries in _m
2195 if [ $kt = m ]; then
2196 # sessID|address.1.22|string|Somewhere-x.y.z
2197 sql=""
2198 err dots from query "select var from par where var like '$col.%';"
2199 for v in `query "select var from par where var like '$col.%';"`; do
2200 # v=address.1.22
2201 st_rowid=${v##*.}
2202 origcol=${v%%.*} # original column derived from
2203 err Updating for $v st_rowid=$st_rowid, partype=`getpartype $v`
2204 ##case `getpartype $v` in
2205 err CASE `gettbl_coltype $tbl/$origcol` in
2206 err edit flag = `getpar action.$v`
2207 case `getpar action.$v` in
2208 rm)
2209 if [ x`getpar confirm.$v` = x"yes" ]; then
2210 newsql="delete from $tb2"
2211 else
2212 echo "削除確認未チェック" | html p
2213 fi ;;
2214 edit)
2215 case `gettbl_coltype $tbl/$origcol` in
2216 image|document|binary)
2217 file=$tmpd/`getparfilename $v`
2218 err type=file=$file
2219 [ -z "$file" ] && continue
2220 bn=${file##*/}
2221 bin="X'"$(hexize $file)"'"
2222 ct=`file --mime-type $file|cut -d' ' -f2`
2223 type=\"file:$ct\"
2224 newsql="update $tb2 set val='$bn', type=$type, bin=$bin"
2225 cachedir=`getcachedir "$tbl/$rowid"`
2226 err getcache tbl/rowid=$tbl/$rowid, rm -r $cachedir
2227 rm -r $cachedir
2228 ;;
2229 *)
2230 newsql="update $tb2 set val=(select val from par where var \
2231 like '$col.%.$st_rowid')"
2232 ;;
2233 esac
2234 ;;
2235 *) # maybe "keep", do not modify value
2236 continue
2237 ;;
2238 esac
2239 # err newsql=$newsql
2240 sql=$sql$nl"$newsql where rowid=$st_rowid;"
2241 done
2243 if [ x"$bin" = x"NULL" ]; then
2244 err repl:normal sql=`echo $sql`
2245 query "$sql
2246 delete from $tb2 where type='string' and val='';"
2247 err repl:normal done
2248 else
2249 sqlfile="$tmpd/sqlf.$$"
2250 echo "$sql" > $sqlfile
2251 err repl:sqlfile=`ls -lF $sqlfile`
2252 query ".read $sqlfile"
2253 err repl:done
2254 fi
2255 # Rest of kt==m: set multiple mode
2256 nr=`getparcount $col`
2257 else
2258 nr=1 # for kt==s, number of records is 1
2259 fi
2261 i=0
2262 while [ $i -lt $nr ]; do
2263 limit="limit 1 offset $i"
2264 i=$((i+1)) # increase beforehand against continue
2265 val=`getvalquote $tbl $col "$limit"`
2266 [ -z "$val" -o x"$val" = x'""' -o x"$val" = x"NULL" ] && continue
2267 err $col=$val
2268 bin=NULL
2269 err partype$col=`getpartype $col "$limit"`
2270 case $ptype in
2271 file) file=$tmpd/`getparfilename $col "$limit"`
2272 err parfile-$col=$file
2273 [ -z "$file" ] && continue
2274 bin="X'"$(hexize $file)"'"
2275 ct=`file --mime-type $file|cut -d' ' -f2`
2276 type=\"file:$ct\" ;;
2277 "*"*) continue ;; # foreign table
2278 *) type=\"string\" ;;
2279 esac
2280 case `gettbl_coltype $tbl/$col` in
2281 password) # special care for password
2282 # name={password,pswd1,pswd2}
2283 p1=`getpar pswd1 "$limit"`
2284 if [ -z "$p1" ]; then
2285 continue # SKIP password setting, if p1 is empty
2286 else
2287 pswd=`getpar pswd "$limit"` p2=`getpar pswd2 "$limit"`
2288 ## err pswd=$pswd
2289 if pwcheck "$pswd"; then
2290 if [ x"$p1" = x"$p2" ]; then
2291 case "$p1" in
2292 ??????????*) ;;
2293 *) echo "10字以上にしてください。" | html p
2294 return 6;;
2295 esac
2296 val="\"`echo $p1|mypwhash`\""
2297 else
2298 echo "2つの新パスワード不一致" | html p
2299 return 7
2300 fi
2301 else
2302 echo "旧パスワード違います" | html p
2303 return 8
2304 fi
2305 fi
2306 ;;
2307 esac
2308 err p2t: "replace into $tb2 values($pval, \"$col\", $type, $val, bin...);"
2309 #query "replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
2310 sql="replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
2311 if [ x"$bin" = x"NULL" ]; then
2312 err Normal-query: `echo $sql`
2313 query "$sql"
2314 else
2315 sqlfile="$tmpd/query.$$"
2316 echo "$sql" > $sqlfile
2317 err sqlfile=`ls -lF $sqlfile`
2318 query ".read $sqlfile"
2319 fi
2320 err p2t done
2321 done
2322 done
2323 done
2324 return 0
2325 err donee)
2327 par2table_old() {
2328 # copy current parameters of par into destination table
2329 # $1=dst-table $2=definition-file
2330 # Using $user and $session
2331 rowid=`getpar rowid`
2332 if [ -n "$rowid" ]; then
2333 rm=`getpar rm` cfm=`getpar confirm`
2334 if [ x"$rm$cfm" = x"yesyes" ]; then
2335 sq $db "delete from $1 where rowid=$rowid and owner=\"$user\""
2336 return
2337 fi
2338 fi
2339 cat $2 \
2340 | (cols=""
2341 while IFS=: read prompt name type args; do
2342 [ x"$name" = x"stage" ] && continue
2343 if [ -n "$rowid" ]; then
2344 val=`getpar $name|sed -e 's/\"/\"\"/g'`
2345 sq $db "update $1 set $name=\"$val\" where rowid=$rowid and owner=\"$user\""
2346 else
2347 eav=$eav${eav+,}" max(case var when '$name' then val end)"
2348 fi
2349 done
2350 [ -n "$rowid" ] && return
2351 cond="where sessid='$session' group by sessid"
2352 sq $db "replace into $1 select $eav,\"$user\" from par $cond"
2353 # Think over again about putting $user
2356 genform() {
2357 # $1 = form definition file
2358 # $2, $3 (optional)= table name and ROWID
2359 # If $GF_VIEWONLY set and nonNull, output values without form
2360 # If $GF_HIDDEN set, use it hidden values
2361 # If $GF_OWNER set, use it as value of name="owner"
2362 # If $GF_STAGE set, use it as value of name="stage"
2363 forms="" hiddens="" rowid=$3
2364 if [ ! -e "$1" ]; then
2365 echo "そのようなデータベースはないようです($2)。" | html p
2366 return
2367 elif [ -n "$2" ]; then
2368 err genform1: "select * from $2 where rowid='$rowid'"
2369 rec=`query "select * from $2 where rowid='$rowid';"`
2370 if [ -z "$rec" ]; then
2371 pk=`gettblpkey $2`
2372 ###rec=`sq $db "select rowid from $2 where $pk='$rowid'"`
2373 err "select rowid from $2 where $pk='$rowid';"
2374 rec=`query "select rowid from $2 where $pk='$rowid';"`
2375 err rec-rowid=$rec
2376 rowid=$rec
2377 rec=$3
2378 fi
2379 if [ -z "$rec" ]; then
2380 echo "そんなレコードはないみたいね..." | html p
2381 return
2382 fi
2383 fi
2384 if [ -z "$GF_VIEWONLY" ]; then
2385 rm='<input id="rm" name="rm" type="checkbox"
2386 value="yes"><label for="rm">このエントリの削除</label>
2387 <span>ほんとうに消しますよ(確認)!
2388 <input name="confirm" type=checkbox value="yes">はい</span>'
2389 fi
2390 # Image Cache dir
2391 err genform: getcache=$2/$rowid
2392 td=`getcachedir "$2/$rowid"`
2393 while IFS=: read prompt name keytype type args; do
2394 [ -z "${prompt%%\#*}" ] && continue # skip comment line(#)
2395 sp="${args:+ }"
2396 form="" val=""
2397 if [ -n "$rowid" ]; then
2398 # err genform2a: Seeking for "$2.$name, type=$type"
2399 val=`getvalbyid $2 $name $rowid $td`
2400 err genform3a: getvalbyid $2 $name $rowid $td
2401 err genform3b: val="[$val]"
2402 fi
2403 if [ -n "$GF_VIEWONLY" ]; then
2404 is_hidden "$2" "$name" && continue
2405 fi
2406 case "$type" in
2407 text*)
2408 cgiform=cgi_multi_$type
2409 if [ -s $td/$name.count -a -n "$val" ]; then
2410 form=`$cgiform $name $td`
2411 val=$(echo "$val"|
2412 while read fn; do
2413 echo "<tr><td>`cat $td/$fn`</td></tr>$nl"
2414 done)
2415 val="<table>$nl$val$nl</table>"
2416 else
2417 #form="<input name=\"$name\" value=\"$val\" type=\"$type\"$sp$args>$nl"
2418 err genform: cgi_$type $name $val "$args"
2419 form=`cgi_$type $name "$val" "$args"`
2420 fi
2421 ;;
2422 [Rr][Aa][Dd][Ii][Oo])
2423 fh="<label><input type=\"radio\" name=\"$name\""
2424 form="`echo $args|sed -e \
2425 \"s,\([^ =][^=]*\)=\([^= ][^= ]*\),$fh value=\\"\2\\">\1</label>,g\"`"
2426 ;;
2427 [Cc][Hh][Ee][Cc][Kk][Bb][Oo][Xx])
2428 form="<label><input type=\"checkbox\" name=\"$name\" value=\"${args#*=}\">${args%=*}</label>"
2429 ;;
2430 [Ss][Ee][Ll][Ee][Cc][Tt])
2431 fh="<select name=\"$name\">$nl"
2432 form=$(for l in $args; do
2433 echo "<option value=\"${l#*=}\">${l%=*}</option>"
2434 done)
2435 if [ -n "$val" ]; then
2436 form=`echo $form|sed -e "s,\(value=.$val.\),\\1 selected,"`
2437 fi
2438 form="$fh$form</select>"
2439 ;;
2440 [Ii][Mm][Aa][Gg][Ee]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Bb]inary)
2441 if [ -s $td/$name.count ]; then
2442 form=`cgi_multi_file $name $td "$args"`
2443 if [ -n "$val" ]; then
2444 hrfb="$myname?showattc+$2_m"
2445 val=$(echo "$val" \
2446 | while read fn; do
2447 data=`percenthex $td/$fn`
2448 #ct=`cat $td/$fn.content-type`
2449 ct=`file --mime-type $td/$fn|cut -d' ' -f2`
2450 ri=`cat $td/$fn.rowid`
2451 ## err fn=$fn, name=$name, ri=$ri; ls -lF $td 1>&3
2452 #imgsrc="<img src=\"data:$ct,$data\">"
2453 #echo "<a href=\"$hrfb+$ri\">$imgsrc</a><br>"
2454 iconhref $td/$fn "$hrfb+$ri" ""
2455 done)
2456 fi
2457 else
2458 form="<input type=\"file\" name=\"$name\" $args>"
2459 if [ -n "$val" ]; then
2460 imgs=$(echo "$val"\
2461 |while read fn;do
2462 data=`percenthex $td/$fn`
2463 echo "<img src=\"data:image/png,$data\">$fn<br>"
2464 done)
2465 form=$form"<br>$imgs"
2466 val=$imgs # 2015-06-15
2467 else
2468 form="<input type=\"file\" name=\"$name\" $args>"
2469 fi
2470 fi
2471 ;;
2472 [Hh][Ii][Dd][Dd][Ee][Nn])
2473 if [ -n "$GF_STAGE" -a x"$name" = x"stage" ]; then
2474 args="value=\"$GF_STAGE\""
2475 fi
2476 form="<input type=\"hidden\" name=\"$name\" $args>"
2477 prompt='' # Remove prompt
2478 ;;
2479 [Aa][Uu][Tt][Hh][Oo][Rr])
2480 form="<input type=\"hidden\" name=\"author\" value=\"$user\">"
2481 prompt="" ;;
2482 [Oo][Ww][Nn][Ee][Rr])
2483 val=${GF_OWNER:-$val}
2484 val=${val:-$user}
2485 form="<input type=\"hidden\" name=\"owner\" value=\"$val\">"
2486 prompt="" ;;
2487 [Uu][Ss][Ee][Rr])
2488 # XXX: is null $user ok?
2489 #form="<input type=\"hidden\" name=\"user\" value=\"$user\">"
2490 [ -n "$GF_VIEWONLY" ] && continue
2491 form="$user"
2492 ;;
2493 [Pp]assword)
2494 [ -n "$GF_VIEWONLY" ] && continue
2495 form="`cgi_passwd`"
2496 val=""
2497 ;;
2498 [Ss][Ee][Rr][Ii][Aa][Ll]|[Ss][Tt][Aa][Mm][Pp])
2499 if [ -z "$rowid" ]; then
2500 val=$((($(date +%s)-1433084400)/10))c$$
2501 fi
2502 ## form="<input type=\"hidden\" name=\"serial\" value=\"$val\">"
2503 ## 2015-07-31
2504 form="<input type=\"hidden\" name=\"$name\" value=\"$val\">"
2505 prompt="" ;;
2506 [Ss][Ee][Ss][Ss][Ii][Oo][Nn])
2507 prompt=""
2508 ;;
2509 parent|path|blog*)
2510 prompt=""
2511 ;;
2512 "*"*)
2513 tail=$tail"``"
2514 continue ;;
2515 esac
2516 if [ -n "$prompt" ]; then
2517 if [ -n "${GF_VIEWONLY}" ]; then
2518 form=$val
2519 else
2521 fi
2522 forms=$forms" <tr class=\"$name\"><th>$prompt</th><td>$form</td></tr>$nl"
2523 else
2524 hiddens=$hiddens$nl"$form"
2525 fi
2526 done < $1
2527 # enctype="multipart/form-data"
2528 cat<<EOF
2529 <form action="${GF_ACTION:-$myname}" method="POST" enctype="multipart/form-data">
2530 ${rowid:+$rm}
2531 <table class="b $2">
2532 $forms
2533 </table>$hiddens
2534 ${GF_STAGE:+`cgi_hidden stage $GF_STAGE`}
2535 ${rowid:+<input type="hidden" name="rowid" value="$rowid">}
2536 EOF
2537 if [ -z $GF_VIEWONLY ]; then
2538 cat<<EOF
2539 <input type="submit" name="sub" value="OK">
2540 <input type="reset" name="res" value="Reset">
2541 EOF
2542 fi
2543 cat<<EOF
2544 </form>
2545 $tail
2546 EOF
2548 edittable() {
2549 # $1=form-def $2=table $3 rowid
2550 genform "$@"
2552 viewtable() {
2553 GF_VIEWONLY=1 genform "$@"
2555 showattc() {
2556 # $1=table_m $2=rowid
2557 err \$1=$1 \$2=$2
2558 if ! isfilereadable $user $1 $2; then
2559 contenttype; echo
2560 echo "このファイルは管理者のみしか見られません" | html p
2561 putfooter; exit
2562 fi
2563 idir=`umask 002; mktempd` || exit 1
2564 # tmpfiles=$tmpfiles"${tmpfiles+ }$idir"
2565 bin=$idir/$myname-$$.bin
2566 sql="select quote(bin) from $1 where rowid='$2';"
2567 err showattc: sql: $sql
2568 sq $db "$sql" | unhexize > $bin
2569 tv=`query "select type,val from $1 where rowid='$2';"`
2570 type=${tv%\|*} fn=${tv#*\|}
2571 err tv=$tv type=$type fn=$fn, tp2=${tv%\|*}
2572 ct=${type#file:}
2573 case $ct in # all text/* changed to text/plain
2574 text/*)
2575 charset=`nkf -g $bin|cut -d' ' -f1`
2576 case $charset in
2577 ASCII*) charset="" ;;
2578 esac
2579 ct="text/plain${charset:+; charset=$charset}"
2580 ;;
2581 esac
2582 contenttype "$ct"
2583 echo "Content-Disposition: filename=\"$fn\""
2584 echo "Content-Length: " `cat $bin | wc -c`; echo
2585 #echo "Content-Type: " ${type#file:}; echo
2586 cat $bin
2589 # Some default stupid handler on CGI values
2591 default_storedb() {
2592 # ARG: $1=table-def-file
2593 # RET: $tbl=table-name, $col=mail-column, $cols=columns
2594 tbl=`basename $1`
2595 tbl=${tbl%.def}
2596 cols="`grep :text $1|cut -d: -f2`"
2597 col=`echo "$cols"|head -1`
2598 vcol=`getpar $col`
2599 err default0: \$1=$1 col=$col cols="[$cols]" vcol=$vcol
2600 if [ -n "$vcol" ]; then
2601 par2table $1
2602 else
2603 return 2 # No insertion occurred
2604 fi
2607 default_view() { # $1=def-file
2608 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
2609 ## DT_VIEW="edittable+$tbl" dumptable html $tbl "name memo file" \
2610 default_storedb "$@"
2611 query "select rowid from $tbl order by rowid desc;" \
2612 | while read rowid; do
2613 viewtable $1 $tbl $rowid
2614 done | m4 -D_TITLE_="$tbl" \
2615 -D_FORM_="`genform $1`" \
2616 -D_DUMPTABLE_="syscmd(cat)" \
2617 $layout/html.m4.html $layout/form+dump.m4.html
2619 default_viewtext() { # $1=def-file
2620 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
2621 default_storedb "$@"
2622 DT_VIEW="viewtable+$tbl" dumptable html $tbl "name memo file" \
2623 | m4 -D_TITLE_="$tbl" \
2624 -D_FORM_="`genform $1`" \
2625 -D_DUMPTABLE_="syscmd(cat)" \
2626 $layout/html.m4.html $layout/form+dump.m4.html
2628 default_smail() {
2629 default_storedb "$@"
2630 if [ $? -eq 2 ]; then
2631 m4 -D_TITLE_="入力" \
2632 -D_FORM_="`genform $1`" \
2633 -D_DUMPTABLE_="" \
2634 $layout/html.m4.html $layout/form+dump.m4.html
2635 return
2636 fi
2637 cond=""
2638 for pk in `gettblpkey $tbl`; do
2639 pv=$(sqlquote $(getpar $pk))
2640 cond="$cond${cond:+ and }$pk=$pv"
2641 done
2642 sql="select rowid from $tbl where $cond;"
2643 rowid=`query "$sql"`
2644 err smail1 - "$sql" "-> rowid=$rowid"
2646 while IFS=: read prompt name keytype type args; do # Read from $1
2647 val=`getpar $name`
2648 if [ -n "$val" ]; then
2649 text="$text
2650 $prompt
2651 $name=$val
2652 ---------------------------------------------------------"
2653 fi
2654 case "$type" in
2655 image|document|file)
2656 fn="`getvalbyid $tbl $name $rowid $tmpd`"
2657 fns=$(echo "$fn"|while read fn; do
2658 err mv $tmpd/$fn.orig $tmpd/$fn
2659 mv $tmpd/$fn.orig $tmpd/$fn
2660 rm $tmpd/$fn.rowid # Remove cache flag
2661 err "`ls $tmpd/$fn`"
2662 echo $fn
2663 done)
2664 files="$files $fns"
2665 ;;
2666 esac
2667 done < $1
2668 err FILES=$files "`ls -lF $tmpd`"
2669 subj="from ${REMOTE_ADDR}"
2670 (echo "$url"
2671 echo "への書き込みがありました。"
2672 echo "------"
2673 echo "$text"
2674 ) | (cd $tmpd &&
2675 err LS="`ls -lF`" &&
2676 $mydir/sendmultipart.sh -t "$admin" -s "$subj" $files)
2677 m4 -D_TITLE_="入力完了" $layout/html.m4.html
2678 echo "以下の内容で送信しました。" | html p
2679 viewtable $1 $tbl \
2680 `query "select rowid from $tbl order by rowid desc limit 1;"`
2681 echo "戻る" | html a "href=\"?\""