s4

view s4-funcs.sh @ 151:7bb7086ea0d0

Unclosed tag, fixed
author HIROSE Yuuji <yuuji@gentei.org>
date Mon, 30 Nov 2015 09:52:08 +0859
parents 6ee08d8b0f5f
children f7b4f7e5df2a
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 || exit 1 # Abort if fail to call 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
1364 sqcond="WHERE name='$uname' AND key='profimg' AND type LIKE 'file:image%'"
1365 img=`query "SELECT type FROM user_m $sqcond LIMIT 1;"`
1366 imf=$tmpd/profimg.$$; touch $imf
1367 if [ -n "$img" ]; then
1368 { printf '%s' "<img src=\"data:${img#file:},"
1369 query "SELECT hex(bin) FROM user_m $sqcond LIMIT 1;" \
1370 | sed 's/\(..\)/%\1/g'
1371 echo '">'
1372 } > $imf
1373 fi
1374 nblog=`query "SELECT count(id) FROM blog_s WHERE key='owner' AND \
1375 val='$uname';"`
1376 listblog $uname > $bf
1377 listgroupbytable $formdir/grp.def $cond \
1378 | m4 -D_BODYCLASS_=home -D_TITLE_="spaste(\`$tf')" \
1379 -D_PROFILE_="spaste(\`$pf')$conflink" \
1380 -D_PROFIMG_="spaste(\`$imf')" \
1381 -D_BLOGS_="spaste(\`$bf')" \
1382 -D_NBLOG_="$nblog" \
1383 -D_GROUPS_="syscmd(\`cat')" \
1384 $layout/html.m4.html $layout/home.m4.html
1386 if [ x"$user" = x"$uname" ]; then
1387 # Display NEWS
1388 cond="where 新着 > 0 order by 新着 desc,ctime desc limit 10"
1389 new10=`DT_CHLD=article:blogid \
1390 DT_VIEW=replyblog dumptable html blog "ctime title gecos" "$cond"`
1391 cont=`echo "$new10"|grep "^<TR>"|wc -l`
1392 cont=$((cont-1))
1393 err newcount=$cont
1394 if [ $cont -gt 0 ]; then
1395 echo "全体の新着記事${cont}傑" | html h2
1396 echo "$new10"
1397 fi
1398 cat<<EOF
1399 <div class="fold">
1400 `cgi_checkbox srchall yes id="sa"`<label
1401 for="sa">SNS全体から検索</label>
1402 <div>
1403 EOF
1404 cgi_form searchart<<EOF
1405 <label>`cgi_text kwd`という語を含む記事を全部から検索</label>
1406 EOF
1407 cat<<EOF
1408 </div></div>
1409 EOF
1410 fi
1412 # Record access log
1413 [ -n "$1" ] && [ x"$1" != x"$user" ] && acclog user $1
1415 commission() { # $1=grp-rowid $2=user-rowid
1416 contenttype; echo
1417 err commission: "$@"
1418 gname=`getgroupbyid $1`
1419 echo "グループ $gname 管理者委任" \
1420 | m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1421 if [ -n "$2" ]; then
1422 grp_reg_adm "$@"
1423 else
1424 echo "無効な指定です。普通のアクセスならここに来ないはず。"|html p
1425 fi
1427 listgroupbytable() {
1428 # $1=deffile $2...=condition
1429 tagline=`grep :tag: $1`; shift
1430 and="${1:+and }" where=${1:+where }
1431 href="<a href=\"$myname?grp+"
1432 echo '<div class="listgroup">'
1433 NGsql="select distinct tag from\
1434 (select gname, max(case key when 'tag' then val end) as tag, \
1435 max(case key when 'ctime' then val end) as ctime\
1436 from grp_s group by gname order by ctime);"
1437 sql="select val from grp_s where key='tag' $and$* group by val;"
1438 err ListGRP: query sql="$sql"
1439 for tag in `query "$sql"`
1440 do
1441 err ListGrp: tag=$tag
1442 tn=${tagline%%=${tag}*}
1443 tn=${tn##*[ :]}
1444 sql="select rowid||':'||gname as 'グループ名',説明 from
1445 (select (select rowid from grp g where g.gname=grp_s.gname)
1446 as rowid,
1447 gname,
1448 max(case key when 'gecos' then val end) as '説明',
1449 max(case key when 'tag' then val end) as 'tag',
1450 max(case key when 'mtime' then val end) as mtime from grp_s
1451 $where$* group by gname having tag='$tag' order by mtime desc);"
1452 err PersonalGroupList= `echo $sql`
1453 echo "<h2>$tn</h2>"
1454 echo '<table class="b listgroup">'
1455 sq -header -html $db "$sql" \
1456 | sed "s,\(<TR><TD>\)\([0-9]*\):\([^ ]*\)</TD>,\1$href\2\">\3</a>,"
1457 echo '</table>'
1458 done
1459 echo '</div>'
1461 iconhref() (
1462 # $1=icon-file, $2=Href $3=title $4...=anchor
1463 data=`percenthex $1`
1464 ct=`file --mime-type $1|cut -d' ' -f2`
1465 err iconhref: \$1=$1 \$2=$2 \$3="$@"
1466 href=$2; title=$3; shift 3
1467 echo "<a href=\"$href\"><img title=\"$title\" src=\"data:$ct,$data\">$@</a>"
1469 iconhref2() (
1470 # $1=icon-file, $2=Href $3=title $4...=anchor
1471 src=$1
1472 href=$2; title=$3; shift 3
1473 echo "<a href=\"$href\"><img title=\"$title\" src=\"$src\">$@</a>"
1475 listentry() (
1476 # $1=user/group $2=SearchKeyword $3=condition(if any)
1477 # Referring variable $iamowner=$grp to attach owner-request links
1478 err listentry: \$1=$1 \$2=$2 \$3=$3
1479 cond=''
1480 offset=`getpar offset`
1481 offset=${offset%%[!0-9]*}
1482 offset=$((offset + 0)) # change to numeric forcibly
1483 [ $offset -lt 0 ] && offset=0
1484 limit=30
1485 dir=`getcachedir "$1"`
1486 if [ x"$1" = x"user" ]; then
1487 hrb="$myname?home"
1488 deficon=person-default.png
1489 entity="ユーザ" tbl=user link=rowid nm=name stage=mems
1490 gcs=gecos
1491 else # if group
1492 hrb="$myname?grp"
1493 deficon=group-default.png
1494 entity="グループ" tbl=grp link=rowid nm=gname stage=grps
1495 gcs=name
1496 tagline=`grep :tag: $formdir/grp.def|cut -d: -f5-`
1497 if [ -n "$tagline" ]; then
1498 tagconv=`echo $tagline|sed 's/\([^= :]*\)=\([^= :]*\)/-D\2=\1/g'`
1499 err tagconv=$tagconv
1500 fi
1501 fi
1502 if [ ! -d $dir ]; then
1503 mkdir -p $dir
1504 fi
1505 if [ ! -s $dir/$deficon ]; then
1506 convert -geometry $thumbxy $imgdir/$deficon $dir/$deficon
1507 fi
1508 if [ -n "$2" ]; then
1509 cond="where nick like '%$2%' or b.name like '%$2%'"
1510 fi
1512 # XX: これ複雑すぎるかな。もっとシンプルにしたい。$3条件も。2015-07-08
1513 # grpは呼出し元の動的スコープ変数でよくないな...
1514 ##qgrp=`sqlquote $grp`
1515 getgrp="(select gname from grp where rowid=${rowid:--1})"
1516 sql="select a.rowid, a.$link, coalesce(b.$gcs, a.$nm) as nick,
1517 coalesce(b.gecos, a.$nm) as name,
1518 b.tag,
1519 case when a.$nm in (select user from grp_adm
1520 where gname=$getgrp) then '(管理者)'
1521 when '$user' in (select user from grp_adm where gname=a.$nm)
1522 then '(ADMIN)'
1523 when '$iamowner' = '' then ''
1524 else ',not='||a.rowid end as ownerlink
1525 from $tbl a left join
1526 (select $nm as name,
1527 max(case key when 'gecos' then val end) as gecos,
1528 max(case key when 'tag' then val end) as tag
1529 from ${tbl}_s group by $nm)
1530 b on a.$nm=b.name $cond $3
1531 order by b.tag desc, a.rowid asc"
1532 err LE:sql.1="$sql"
1533 total=`query "with x as ($sql) select count(*) from x;"`
1534 echo "${entity} 一覧" | html h2
1535 if [ $total -gt $limit ]; then
1536 echo '<div class="right">'
1537 cgi_form $stage <<EOF
1538 <label>次の語を含む${entity}で検索:
1539 `cgi_text kwd $kwd`</label>
1540 EOF
1541 echo '</div>'
1542 fi
1543 cat<<EOF
1544 <p>${total}件中の$((offset+1))件めから${kwd:+" - 検索語: $kwd"}</p>
1545 EOF
1546 if [ $((offset+limit)) -lt $total ]; then
1547 cat<<EOF
1548 <div class="right"><form action="$myname" method="POST">
1549 `cgi_submit 次の${limit}件`
1550 `cgi_hidden kwd "$kwd"`
1551 `cgi_hidden stage "$stage"`
1552 `cgi_hidden offset $((offset + limit))`</form></div>
1553 EOF
1554 fi
1555 if [ $offset -gt 0 ]; then
1556 cat<<EOF
1557 <form action="$myname" method="POST">
1558 `cgi_submit 前の${limit}件`
1559 `cgi_hidden stage "$stage"`
1560 `cgi_hidden kwd "$kwd"`
1561 `cgi_hidden offset $((offset - limit))`</form>
1562 EOF
1563 fi
1565 err ListEntry: `echo "$sql"\;`
1567 query "$sql limit $limit ${offset:+offset $offset};" \
1568 | while IFS='|' read id lnk name gecos tag ownerp; do
1569 err name=$name owner=$ownerp lnk=$lnk
1570 err newlnk=$lnk
1571 files=`getvalbyid $tbl profimg $id $dir`
1572 # Pick up only first icon
1573 echo "<div class=\"iconlist xy$thumbxy\"><p class=\"tag _$tag\">$tag</p>" \
1574 | m4 $tagconv
1575 if [ -n "$files" ]; then
1576 icon=`echo "$files"|head -1`
1577 iconhref $dir/$icon "$hrb+$lnk" "$gecos"
1578 else
1579 iconhref $dir/$deficon "$hrb+$lnk" "$gecos"
1580 fi
1581 echo "<br>$name${ownerp:+<br>$ownerp}"
1582 echo "</div>"
1583 done
1585 listmember() {
1586 listentry user "$@"
1588 listgroup() {
1589 listentry group "$@"
1591 showgroup() { # $1=group-rowid
1592 # gname=`getpar gname`
1593 # if [ -n "$gname" ]; then
1594 # err UPdating/Removing of group:::::::
1595 # # See ALSO same job in groupman()
1596 # newgname=`echo "$gname"|tr -d '\"'"'"`
1597 # ###newgname=$gname
1598 # err gname=$gname newgname=$newgname
1599 # if [ x"$newgname" != x"$gname" ]; then
1600 # err NewGNAME: gname=$newgname
1601 # gname=$newgname
1602 # echo "使用禁止文字を除去し $gname としました。" | html p
1603 # replpar gname string "$gname"
1604 # fi
1605 # par2table $formdir/grp.def
1606 # fi
1607 grp=`getgroupbyid $1`
1608 err showgroup2: grp=$grp qgrp="[$(sqlquote $grp)]"
1609 if isgroup "$grp"; then
1610 tf=$tmpd/title.$$
1611 echo "グループ $grp" > $tf
1612 showgroupsub $formdir/grp.def "$1" | \
1613 m4 -D_TITLE_="spaste(\`$tf')" \
1614 -D_FORM_="syscmd(\`cat')" \
1615 -D_DUMPTABLE_="" \
1616 $layout/form+dump.m4.html
1617 else # if $grp is removed at par2table
1618 listgroup
1619 fi
1621 showgroupsub() {
1622 # $1=def-file $2=group-rowid
1623 rowid=$2
1624 grp=`getgroupbyid $2`
1625 qgrp=`sqlquote $grp`
1626 #rowid=`sq $db "select rowid from grp where gname=$qgrp"`
1627 if [ -z "$rowid" ]; then
1628 #rowid=`sq $db "select rowid from grp where rowid=$grp"`
1629 #grp=`sq $db "select gname from grp where rowid=$grp"`
1630 echo "showgroupsub: invalid argument($1 $2)" | html p
1631 return
1632 fi
1633 val=`getvalbyid grp profimg $rowid $tmpd`
1634 # 6/14の次グループのHOMEで出す情報を作る Done
1635 viewtable $1 grp $rowid
1636 if isgrpowner "$user" "$grp"; then
1637 echo "<p><a href=\"?groupconf+$rowid\">グループ情報の編集</a>"
1638 iamowner=$rowid
1639 fi
1640 if ismember "$user" "$grp"; then
1641 echo "${iamowner:+ / }<a href=\"?blog+$rowid\">グループの新規話題作成</a>"
1642 echo "/ <a href=\"?grpaction+$rowid\">メンバーを個別選択しての操作</a></p>"
1643 # div.fold input[type="checkbox"]:checked ~ div {display: block;}
1644 cat<<EOF
1645 <form action="?send2mem" method="POST" enctype="multipart/form-data">
1646 <div class="fold">
1647 `cgi_checkbox send yes id="send"`<label
1648 for="send">グループ全員にメッセージ送信</label>
1649 <div>
1650 `cgi_textarea message "" "cols=60"`
1651 `cgi_submit 送信`
1652 `cgi_reset リセット`
1653 </div>
1654 `cgi_hidden grp $rowid`
1655 </div></form>
1656 EOF
1657 fi
1658 # 加入ボタン + 加入者リスト
1659 err ismember $user $grp
1660 ismember "$user" "$grp" && ismem='checked' || nomem='checked'
1661 # このグループでの加入アドレス
1662 eml=`query "select val from grp_mem_s where gname='$2' and user='$user' \
1663 and key='email';"`
1664 err EML: "select val from grp_mem_s where gname='$2' and user='$user' \
1665 and key='email';"
1666 err email=$eml
1667 cat <<EOF
1668 <div class="fold">
1669 `cgi_checkbox reg yes id="reg"`<label
1670 for="reg">自身の参加状態を操作する</label>
1671 <div>
1672 EOF
1673 cgi_form grp <<EOF
1674 <p>このグループに</p>
1675 <table class="b">
1676 <tr><th>メンバーとして</th><td>
1677 <label>`cgi_radio joingrp "yes" $ismem`参加</label> /
1678 <label>`cgi_radio joingrp "no" $nomem`参加しない</label></td></tr>
1679 <tr><th>参加する場合のメイルアドレス<br>
1680 <small>(メインのアドレスとは違うものにする場合に記入<br>
1681 同じでよい場合は空欄に)</small></th>
1682 <td>`cgi_text email $eml`</td></tr>
1683 </table>
1684 `cgi_hidden grp $rowid`
1685 EOF
1686 if [ x`getgroupattr $grp regmode` = x'moderated' -a -z "$ismem" ]; then
1687 echo "moderated (承認加入の)グループなので実際に参加できるのは
1688 グループ管理者が承認操作をした後になります。" | html p 'class="warn"'
1689 fi
1690 echo '</div></div>'
1691 echo '<h2>話題一覧</h2>'
1692 cgi_form searchart<<EOF
1693 <label>`cgi_text kwd`という語を含むコメントを検索</label>
1694 `cgi_hidden owner $grp`
1695 EOF
1696 cond="where a.id in (select id from blog_s where key='owner' and val=$qgrp) order by ctime desc"
1697 DT_CHLD=article:blogid \
1698 DT_VIEW=replyblog dumptable html blog 'ctime title heading' "$cond"
1700 getgname="(select gname from grp where rowid=$rowid)"
1701 c="group by b.name having b.name in (select user from grp_mem where gname=$getgname)"
1702 cm="?commission+$rowid"
1703 thumbxy=50x50 listmember "" "$c" \
1704 |sed -e "s|\(<br>\),not=\(.*\)|\1<a href=\"$cm+\2\">管理者委託</a>|"
1706 grpaction() { # $1=group-rowid
1707 err GRP_ACTION:IN
1708 grid=${1:-`getpar grp`}
1709 grp=`getgroupbyid "$grid"`
1710 if [ -z "$grp" ]; then
1711 echo "無効な指定です。" | html p; return
1712 fi
1713 if ! ismember $user $grp; then
1714 echo "加入者のみに許可された操作です。" | html p; return
1715 fi
1716 echo "グループ $grp 個別選択操作" \
1717 | m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1719 isowner=""
1720 isgrpowner "$user" "$grp" && isowner="yes"
1721 usel=`getpar usel`
1722 if [ -n "$usel" ]; then
1723 uids=$(echo `echo $usel`|tr ' ' ',')
1724 err grpaction-1: grp=$grp, `echo $sql`
1725 text=`getpar text`
1727 rm=`getpar rm` cfm=`getpar confirm`
1728 err rm=$rm cfm=$cfm
1729 if [ x"$rm" = x"yes" ]; then
1730 if [ "$isowner" ]; then
1731 if [ x"$rm$cfm" = x"yesyes" ]; then
1732 # Eliminate
1733 cond="where gname=(select gname from grp where rowid=$grid) and user in (select name from user where rowid in ($uids))"
1734 for tbl in grp_mem grp_mem_s grp_mem_m; do
1735 sql="delete from $tbl $cond;"
1736 # echo "sql=$sql"
1737 query "$sql"
1738 err rmGRPuser "$sql"
1739 done
1740 num=`query "select count(*) from user where rowid in ($uids);"`
1741 #err num=$num
1742 if [ 0$num -gt 0 ]; then
1743 sql="select coalesce(b.val,a.name) from user a left join \
1744 user_s b on a.name=b.name and key='gecos' where a.rowid in ($uids);"
1745 # err `echo "$sql"`
1746 html pre<<EOF
1747 以下の${num}名のグループ $grp 登録を解除しました。
1748 `query "$sql"`
1749 EOF
1750 fi
1751 else
1752 echo "確認のチェックがないのでやめておきます。" | html p
1753 return
1754 fi
1755 else # not Group Owner
1756 echo "グループ管理者でないのでメンバー操作はできません。" | html p
1757 return
1758 fi
1759 cat<<EOF
1761 EOF
1762 elif [ -n "$text" ]; then # if NOT removal mode
1763 smail "`email4groupbyuid "$grp" $usel` $user" \
1764 "`gecos $user` さんからのメッセージ" <<EOF
1765 $url
1766 のグループ「$grp」のメンバーである `gecos $user` さんから、
1767 あなた宛へのメッセージです。
1768 ----------------------------------------------------------
1769 $text
1770 EOF
1771 if [ $? = 0 ]; then
1772 echo "Note: 以下のメンバーにメッセージを送信しました。" | html p
1773 sql="select coalesce(b.val, a.name) from
1774 (select name from user where rowid in ($uids)) a
1775 left join user_s b on a.name=b.name and b.key='gecos';"
1776 html pre<<EOF
1777 `query "$sql"`
1778 (送信者である `gecos $user` さんも含まれます)
1779 EOF
1780 err SendDone: `echo $sql`
1781 fi
1782 fi
1783 fi
1784 # New entry
1785 sql="select u.rowid||','||j.* from user u
1786 join (select a.user as name,coalesce(b.val,a.user)
1787 from (select gname,user from grp_mem
1788 where gname=(select gname from grp where rowid=$1))
1789 a left join (select gname,user,val from grp_mem_s where key='email')
1790 b using(gname,user))
1791 j using(name) order by u.name;"
1792 sql="select a.rowid||','||coalesce(val,a.name) as name from
1793 (select rowid,name from user where name in
1794 (select user from grp_mem where
1795 gname=(select gname from grp where rowid=$grid)))
1796 a left join user_s on a.name=user_s.name and key='gecos'
1797 order by name;"
1798 err grpaction: `echo $sql`
1799 b1='<label> <input type="checkbox" name="usel" value="'
1800 b2='"> ' b3='</label>'
1801 tf=$tmpd/title.$$
1802 echo "グループ[$grp]参加メンバーに対する操作" > $tf
1803 excmsg="<div class=\"fold\">
1804 `cgi_radio rm yes ` 下でチェックした人のグループ登録解除
1805 <div>
1806 本当に消します! `cgi_checkbox confirm yes` 確認
1807 <p>この操作による通知は本人に行きません。
1808 あらかじめ通知するか、登録解除してよい状況かしっかり確認してください。</p>
1809 </div>
1810 </div>"
1811 cgi_form grpaction<<EOF \
1812 | sed -e "s|^\(<TR><TD>\)\([0-9]*\),\([^<]*\)|\1$b1\2$b2\3$b3|" \
1813 | m4 -D_TITLE_="spaste(\`$tf')" \
1814 -D_SUBTITLE_="チェック後操作ボタン" \
1815 -D_FORM_="syscmd(cat)" -D_DUMPTABLE_="" \
1816 $layout/form+dump.m4.html
1817 <div class="fold">
1818 `cgi_radio rm send id="sendmsg"`<label
1819 for="sendmsg">下でチェックした人にメッセージを送信する</label>
1820 <div>
1821 `cgi_textarea text "" cols=40`
1822 </div>
1823 </div>
1824 ${isowner:+$excmsg}
1825 <h4>$grp 参加者一覧</h4>
1826 <table>
1827 `sq $db -html "$sql"`
1828 `cgi_hidden grp $grid`
1829 </table>
1830 EOF
1832 editheading() { # $1=rowid-of-heading
1833 rowid=${1%%[!A-Z0-9a-z_]*}
1834 if [ -z "$rowid" ]; then
1835 echo "話題番号が未指定です。" | html p
1836 return
1837 fi
1838 owner=`getvalbyid blog owner $rowid`
1839 title=`getvalbyid blog title $rowid`
1840 GF_ACTION="?blog" edittable $formdir/blog.def blog $rowid \
1841 | m4 -D_TITLE_="修正" \
1842 -D_SUBTITLE_="[$title]@$owner" -D_DIARY_="" \
1843 -D_BLOGS_="" -D_DUMPTABLE_="" \
1844 -D_FORM_="syscmd(\`cat')" \
1845 $layout/html.m4.html $layout/form+dump.m4.html
1847 editart() { # $1=article-rowid $2=blogrowid
1848 rowid=${1%%[!A-Z0-9a-z_]*}
1849 blogrowid=${2%%[!A-Z0-9a-z_]*}
1850 if [ -z "$rowid" -o -z "$blogrowid" ]; then
1851 echo "表示する記事番号が未指定です。" | html p
1852 return
1853 fi
1854 owner=`getvalbyid blog owner $blogrowid`
1855 title=`getvalbyid blog title $blogrowid`
1856 author=`getvalbyid article author $rowid`
1857 err EDITart: owner=$owner, author=$author
1858 if isgrpowner $user $owner; then
1859 : EDIT OK
1860 elif [ x"$owner" != x"$user" -a x"$author" != x"$user" ]; then
1861 echo "本人か所有者しか編集できません." | html p
1862 return
1863 fi
1864 aid=`query "select id from article where rowid=$rowid;"`
1865 tmpout=$tmpd/editart.$$.out
1866 GF_ACTION="?replyblog+$blogrowid#$aid" \
1867 edittable $formdir/article.def article $rowid \
1868 > $tmpout
1869 rm -f /tmp/editart.out
1870 # Cannot use pipelining to m4 with genform() because of stdin stack
1871 m4 -D_TITLE_="コメントの修正" -D_DIARY_="" \
1872 -D_FORM_="syscmd(cat $tmpout)" \
1873 -D_SUBTITLE_="`gecos $owner`の「$title」" \
1874 -D_BLOGS_= -D_DUMPTABLE_= \
1875 $layout/html.m4.html $layout/form+dump.m4.html
1877 send2mem() {
1878 rowid=`getpar grp`
1879 if [ -z "$rowid" ]; then
1880 echo "グループが未指定です。" | html p
1881 return
1882 fi
1883 message=`getpar message`
1884 if [ -z "$message" ]; then
1885 echo "文章を入れてください。" | html p
1886 return
1887 fi
1888 grp=`getgroupbyid $rowid`
1889 members=`collectemail $grp`
1890 # smail rcpt subj (file)
1891 smail "$members" "グループ $grp 宛メッセージ(from `gecos $user`)" <<EOF
1892 $urlbase?grp+$rowid
1893 グループ $grp に所属する
1894 `gecos $user` さんよりメッセージ:
1896 $message
1897 EOF
1898 cat<<EOF
1899 <p>以下の宛先に送信しました。</p>
1900 <pre>
1901 $members
1902 </pre>
1903 <p><a href="?grp+$rowid">グループ $grp</a>に戻る。</p>
1904 EOF
1906 joingrpadmit() {
1907 # $1=yes/no $2=session-key
1908 if [ -z "$2" ]; then
1909 echo "bye bye" | html p; return
1910 fi
1911 t_usr=`session=$2 getpar user`
1912 t_grp=`session=$2 getpar group`
1913 err joingrpadmit: t_usr=$t_usr, t_grp=$t_grp
1914 m4 -D_TITLE_="joingrp" $layout/html.m4.html
1915 if [ -z "$t_usr" -o -z "$t_grp" ]; then
1916 echo "無効な加入依頼です。" | html p
1917 echo "有効期限が切れたか、
1918 他の管理者がいる場合は処理済みの可能性があります。" | html p
1919 return
1920 fi
1921 if ! isgrpowner "$user" $t_grp; then
1922 echo "グループ管理者のみの機能です。" | html p; return
1923 fi
1924 case $1 in
1925 yes) joingrp "$t_grp" "$t_usr" yes "$t_usr" ;;
1926 no) joingrp "$t_grp" "$t_usr" no "$t_usr" ;;
1927 *)
1928 echo "無効な指定です($1)。" | html p
1929 return ;;
1930 esac
1931 gid=$(query "select rowid from grp where gname=`sqlquote $t_grp`;")
1932 rcpts="`getgroupadminmails $t_grp` $user"
1933 err admit: msgdir=$msgdir, rcpts="["$rcpts"]"
1934 body="グループ $t_grp
1935
1936 $t_usr
1937 `[ x$1 = xyes ] && echo 'を追加' || echo 'の解除操作を'`
1938 しました。"
1939 (echo "$body"; echo; echo "$url?grp+$gid") | smail "$rcpts" "joingrp $1"
1940 query "delete from session where id='$2';"
1941 echo "$body" | html p
1944 joingrprequest() {
1945 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
1946 jss="joingrp-`date +%s`-`genrandom 12`"
1947 addsession $jss +${memoplimitdays}days
1948 query "replace into par values('$jss', 'group', 'string', `sqlquote $1`),
1949 ('$jss', 'user', 'string', `sqlquote $user`);"
1950 smail "$(collectemail `getgroupadmins $1`)" "Join request to $1"<<EOF
1951 $url
1952 グループ $1
1953 に加入依頼がありました。
1955 承認する:
1956 $urlbase?joingrpadmit+yes+$jss
1958 白紙に戻す:
1959 $urlbase?joingrpadmit+no+$jss
1960 EOF
1961 echo "管理者に加入依頼を出しました。
1962 ${memoplimitdays}日以内に加入承認操作がされれば加入できますが、
1963 グループ運用方針に懸かることですので直接の問い合わせが重要です。" | html p
1965 joingrp() {
1966 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
1967 err joingrp: \$1=$1 \$2=$2 \$3=$3 \$4=$4
1968 isgrpowner "$user" "$1" && isowner="yes" || isowner=""
1969 err jg:isgrpowner: isowner="$isowner"
1970 if [ -n "$isowner" ]; then
1971 : # GROUP OWNER CAN DO EVERYTHING ABOUT REGISTRATION/RETIREMENT
1972 elif [ x"$2" != x"$user" ]; then # if user is not login user
1973 echo "本人か、グループ管理者しか加入操作はできません。" | html p
1974 return
1975 elif [ x"$3" = x"no" ]; then
1976 : # Do not pursue those who leave
1977 else # adding user is $user itself
1978 case `getgroupattr $1 regmode` in
1979 moderated)
1980 joingrprequest "$@" # Request only
1981 return
1982 ;;
1983 *)
1984 ;;
1985 esac
1986 fi
1987 qgname=`sqlquote $1`
1988 cond="where gname=$qgname and user='$2'"
1989 if [ x"$3" = x"yes" ]; then
1990 query "replace into grp_mem values($qgname, '$2');"
1991 if [ -n "$4" ]; then
1992 if msg=`emaildomaincheck "$4"`; then
1993 err "replace into grp_mem_s values($qgname, '$user', 'email', \
1994 'string', '$4', NULL);"
1995 query "replace into grp_mem_s values($qgname, '$user', 'email', \
1996 'string', '$4', NULL);"
1997 if [ -n "$5" ]; then # as ADMIN
1998 # Coming here means newly created group
1999 sql="select case\
2000 when (select count(*) from grp_mem where gname=$qgname)=1\
2001 then (select user from grp_mem\
2002 where gname=$qgname and user='$user')\
2003 else '' end;"
2004 err NewGrpChk: $sql
2005 if [ -n "`query \"$sql\"`" ]; then
2006 err ADMIN: "replace into grp_adm values($qgname, '$user');"
2007 query "replace into grp_adm values($qgname, '$user');"
2008 fi
2009 fi
2010 else
2011 echo $msg
2012 fi
2013 else
2014 query "delete from grp_mem_s $cond and key='email';"
2015 fi
2016 else
2017 query "delete from grp_mem $cond;
2018 delete from grp_mem_s $cond;
2019 delete from grp_mem_m $cond;"
2020 fi
2022 grp_reg_adm() {
2023 # $1=grp-rowid $2=user-rowid
2024 grp=`getgroupbyid "$1"`
2025 if [ -z "$grp" ]; then
2026 echo "無効なグループIDです" | html p; return
2027 fi
2028 if ! isgrpowner $user "$grp"; then
2029 echo "$grp グループの管理者しかこの操作はできません。" | html p; return
2030 fi
2031 newadm=`query "select name from user where rowid=$2;"`
2032 if [ -z "$newadm" ]; then
2033 echo "指定ユーザIDがおかしいようです。" | html p; return
2034 fi
2035 err GRP_reg_adm: "replace into grp_adm values(`sqlquote $grp`, '$newadm');"
2036 err ismember $newadm $grp
2037 if ismember $newadm $grp; then
2038 # OK, go ahead
2039 getgname="(select gname from grp where rowid=$1)"
2040 query "replace into grp_adm values($getgname, '$newadm');"
2041 # confirm insertion
2042 sql="select * from grp_adm where gname=$getgname and user='$newadm'"
2043 if [ -n "`query \"$sql;\"`" ]; then
2044 echo "追加完了" | html p
2045 else
2046 echo "追加失敗($1 $2)" | html p
2047 fi
2048 fi
2049 showgroup $1
2051 dumptable() {
2052 # $1=mode $2=Table $3=column-list-of-*_s(defaults to *) $4=conditions(if any)
2053 # textのフィールドだけ全てダンプにしたほうがいいか
2054 # $DT_VIEW sets link
2055 # 6/17の次: editリンクじゃなくてスレッドVIEWリンクでいいんちゃう?
2056 ### elink="<a href=\"$myname?edittable+$2+\\2\">EDIT</a>"
2057 VIEW=${DT_VIEW-replyblog}
2058 if [ -n "$VIEW" ]; then
2059 dvlink=" <a href=\"$myname?$VIEW+\\2\">VIE</a><a href=\"$myname?$VIEW+\\2#bottom\">W</a>"
2060 fi
2061 # $DT_CHLD=ChildTable:BindColumn
2062 if [ -n "$DT_CHLD" ]; then
2063 _t=${DT_CHLD%:*} _i=${DT_CHLD#*:}
2064 cntall="(select count($_i) from $_t where $_i=a.id)"
2065 cntnew="(select count(val) from ${_t}_s where key='ctime' \
2066 and id in (select id from $_t where $_i=a.id) \
2067 and val > coalesce((select time from acclog where \
2068 user='$user' and tbl='$2' and rowid=a.rowid),\
2069 '1970-01-01'))"
2070 cnt="$cntnew as '新着', $cntall as '総数',"
2071 dt_class=" td2r td3r"
2072 fi
2073 # Construct join expression
2074 eav="" scols=""
2075 pk=`gettblpkey $2`
2076 substr=${dumpcollen:+"substr(val, 0, $dumpcollen)"}
2077 substr=${substr:-val}
2078 for col in ${3:-`gettbl_s_cols $2`}; do
2079 case $col in
2080 gecos) scols="$scols${scols:+, }${col#}"
2081 continue ;; # built-in column name
2082 *:*) col=${col%:*} as=${col#*:} ;;
2083 *) as=${col} ;;
2084 esac
2085 eav=$eav${eav:+,}" max(case key when '$col' then $substr end) as $as"
2086 scols="$scols${scols:+, }b.$as"
2087 done
2088 #case author when '$user' then a.rowid else '---' end as ID,
2089 sql="select \
2090 a.rowid as ID,\
2091 $cnt\
2092 $scols from $2 a left join\
2093 (select $pk,$eav,
2094 max(case key when 'owner'
2095 then coalesce((select val from user_s us
2096 where us.key='gecos' and us.name=c.val), val) end) as gecos
2097 from ${2}_s c group by $pk) b on a.$pk=b.$pk $4;"
2098 err SQL=`echo "$sql"`
2099 cat<<EOF | sed "s,\(<TR><TD>\)\([1-9][0-9]*\)</TD>,\1$elink$dvlink</TD>,"
2100 <div class="dumptable">
2101 <table class="b$dt_class">
2102 `sq -header -cmd ".mode $1" $db "$sql"`
2103 </table>
2104 </div> <!-- dumptable -->
2105 EOF
2108 par2table() (
2109 # copy current parameters of par into destination table
2110 # $1=definition-file
2111 # Using $user and $session
2112 # Return value:
2113 # 0: Stored successfully
2114 # 1: Insufficient fillings
2115 # 2: No permission to modify the record
2116 # 3: Invalid rowid
2117 # 4: SUCCESS to delete
2118 # 5: Stop deletion for lack of confirm check
2119 # 6: Password length too short
2120 # 7: Password mismatch
2121 # 8: Old password incorrect
2122 rowid=`getpar rowid`
2123 err ...........rowid=$rowid
2124 if [ ! -e $1 ]; then
2125 echo "テーブル定義ファイルが見付かりません" | html p
2126 exit 1
2127 fi
2128 tbl=${1%.def}
2129 tbl=${tbl##*/}
2130 if [ -n "$rowid" ]; then # Modify existing entry
2131 if [ x"$tbl" = x"user" ]; then
2132 rowowner=`query "select name from $tbl where rowid=$rowid;"`
2133 elif [ x"$tbl" = x"grp" ]; then
2134 sql="select gname from $tbl where rowid=$rowid;"
2135 ##err p2t:grp:q $sql
2136 isgrpowner $user "`query $sql`" && rowowner=$user
2137 else
2138 rowowner=`query "select owner from $tbl where rowid=$rowid;"`
2139 rowowner=${rowowner:-`query "select author from $tbl
2140 where rowid=$rowid;"`}
2141 fi
2142 ### err rowowner=$rowowner
2143 if [ x"$user" != x"$rowowner" ]; then
2144 echo "他人のレコードはいじれないの" | html p
2145 return 2
2146 elif [ -z "$rowowner" ]; then
2147 echo "指定したレコードはないみたい" | html p
2148 return 3
2149 fi
2150 rm=`getpar rm` cfm=`getpar confirm`
2151 # Editing existent entry
2152 if [ x"$rm" = x"yes" ]; then
2153 if [ x"$rm$cfm" = x"yesyes" ]; then
2154 query "delete from $tbl where rowid=$rowid;"
2155 return 4
2156 else
2157 echo "消去確認のチェックがないので消さなかったの..." | html p
2158 return 5
2159 fi
2160 fi
2161 fi
2162 # XX: Subshelling here is unnecessary 2015-07-05
2163 (ts=${tbl}_s tm=${tbl}_m val="" pval="" formaster=""
2164 if [ -n "$rowid" ]; then
2165 # Update of existing record
2166 for col in `gettblcols $tbl`; do
2167 val=`getparquote $col`
2168 [ -z "$val" ] && continue
2169 err query "update $tbl set $col=$val where rowid=$rowid"
2170 query "update $tbl set $col=$val where rowid=$rowid;"
2171 done
2172 # Then, set up $pval for further insertion of tbl_s and tbl_m
2173 for col in `gettblpkey $tbl`; do
2174 val=`query "select $col from $tbl where rowid=$rowid;"|sed -e 's/\"/\"\"/g'`
2175 pval="$pval${pval:+, }\"$val\""
2176 done
2177 else
2178 # New entry
2179 # Generate values() for primary keys
2180 for col in `gettblpkey $tbl`; do
2181 # Genuine primary keys for _m and _s
2182 val=`getvalquote $tbl $col`
2183 [ -z "$val" ] && continue
2184 pval="$pval${pval:+, }$val"
2185 done
2186 err pval=$pval
2187 for col in `gettblfkey $tbl`; do
2188 # args for values() to insertion into master table
2189 val=`getvalquote $tbl $col`
2190 [ -z "$val" ] && continue
2191 formaster=$formaster"${formaster:+, }$val"
2192 done
2193 formaster="$pval${formaster:+, }$formaster"
2194 err formaster=$formaster
2195 if [ -z "$formaster" ]; then
2196 echo "項目を全て埋めてください" | html pre
2197 return 1
2198 fi
2199 err "replace into $tbl values($formaster);"
2200 query "replace into $tbl values($formaster);"
2201 ## Insertion to master table, done
2202 fi
2204 for kt in s m; do
2205 tb2=${tbl}_$kt
2206 for col in `gettbl_${kt}_cols $tbl`; do
2207 ptype=`getpartype $col "limit 1"`
2209 # First, check update of existing entries in _m
2210 if [ $kt = m ]; then
2211 # sessID|address.1.22|string|Somewhere-x.y.z
2212 sql=""
2213 err dots from query "select var from par where var like '$col.%';"
2214 for v in `query "select var from par where var like '$col.%';"`; do
2215 # v=address.1.22
2216 st_rowid=${v##*.}
2217 origcol=${v%%.*} # original column derived from
2218 err Updating for $v st_rowid=$st_rowid, partype=`getpartype $v`
2219 ##case `getpartype $v` in
2220 err CASE `gettbl_coltype $tbl/$origcol` in
2221 err edit flag = `getpar action.$v`
2222 case `getpar action.$v` in
2223 rm)
2224 if [ x`getpar confirm.$v` = x"yes" ]; then
2225 newsql="delete from $tb2"
2226 else
2227 echo "削除確認未チェック" | html p
2228 fi ;;
2229 edit)
2230 case `gettbl_coltype $tbl/$origcol` in
2231 image|document|binary)
2232 file=$tmpd/`getparfilename $v`
2233 err type=file=$file
2234 [ -z "$file" ] && continue
2235 bn=${file##*/}
2236 bin="X'"$(hexize $file)"'"
2237 ct=`file --mime-type $file|cut -d' ' -f2`
2238 type=\"file:$ct\"
2239 newsql="update $tb2 set val='$bn', type=$type, bin=$bin"
2240 cachedir=`getcachedir "$tbl/$rowid"`
2241 err getcache tbl/rowid=$tbl/$rowid, rm -r $cachedir
2242 rm -r $cachedir
2243 ;;
2244 *)
2245 newsql="update $tb2 set val=(select val from par where var \
2246 like '$col.%.$st_rowid')"
2247 ;;
2248 esac
2249 ;;
2250 *) # maybe "keep", do not modify value
2251 continue
2252 ;;
2253 esac
2254 # err newsql=$newsql
2255 sql=$sql$nl"$newsql where rowid=$st_rowid;"
2256 done
2258 if [ x"$bin" = x"NULL" ]; then
2259 err repl:normal sql=`echo $sql`
2260 query "$sql
2261 delete from $tb2 where type='string' and val='';"
2262 err repl:normal done
2263 else
2264 sqlfile="$tmpd/sqlf.$$"
2265 echo "$sql" > $sqlfile
2266 err repl:sqlfile=`ls -lF $sqlfile`
2267 query ".read $sqlfile"
2268 err repl:done
2269 fi
2270 # Rest of kt==m: set multiple mode
2271 nr=`getparcount $col`
2272 else
2273 nr=1 # for kt==s, number of records is 1
2274 fi
2276 i=0
2277 while [ $i -lt $nr ]; do
2278 limit="limit 1 offset $i"
2279 i=$((i+1)) # increase beforehand against continue
2280 val=`getvalquote $tbl $col "$limit"`
2281 [ -z "$val" -o x"$val" = x'""' -o x"$val" = x"NULL" ] && continue
2282 err $col=$val
2283 bin=NULL
2284 err partype$col=`getpartype $col "$limit"`
2285 case $ptype in
2286 file) file=$tmpd/`getparfilename $col "$limit"`
2287 err parfile-$col=$file
2288 [ -z "$file" ] && continue
2289 bin="X'"$(hexize $file)"'"
2290 ct=`file --mime-type $file|cut -d' ' -f2`
2291 type=\"file:$ct\" ;;
2292 "*"*) continue ;; # foreign table
2293 *) type=\"string\" ;;
2294 esac
2295 case `gettbl_coltype $tbl/$col` in
2296 password) # special care for password
2297 # name={password,pswd1,pswd2}
2298 p1=`getpar pswd1 "$limit"`
2299 if [ -z "$p1" ]; then
2300 continue # SKIP password setting, if p1 is empty
2301 else
2302 pswd=`getpar pswd "$limit"` p2=`getpar pswd2 "$limit"`
2303 ## err pswd=$pswd
2304 if pwcheck "$pswd"; then
2305 if [ x"$p1" = x"$p2" ]; then
2306 case "$p1" in
2307 ??????????*) ;;
2308 *) echo "パスワードは10字以上にしてください。" | html p
2309 return 6;;
2310 esac
2311 val="\"`echo $p1|mypwhash`\""
2312 else
2313 echo "2つの新パスワード不一致" | html p
2314 return 7
2315 fi
2316 else
2317 echo "旧パスワード違います" | html p
2318 return 8
2319 fi
2320 fi
2321 ;;
2322 esac
2323 err p2t: "replace into $tb2 values($pval, \"$col\", $type, $val, bin...);"
2324 #query "replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
2325 sql="replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
2326 if [ x"$bin" = x"NULL" ]; then
2327 err Normal-query: `echo $sql`
2328 query "$sql"
2329 else
2330 sqlfile="$tmpd/query.$$"
2331 echo "$sql" > $sqlfile
2332 err sqlfile=`ls -lF $sqlfile`
2333 query ".read $sqlfile"
2334 fi
2335 err p2t done
2336 done
2337 done
2338 done
2339 return 0
2340 err donee)
2342 par2table_old() {
2343 # copy current parameters of par into destination table
2344 # $1=dst-table $2=definition-file
2345 # Using $user and $session
2346 rowid=`getpar rowid`
2347 if [ -n "$rowid" ]; then
2348 rm=`getpar rm` cfm=`getpar confirm`
2349 if [ x"$rm$cfm" = x"yesyes" ]; then
2350 sq $db "delete from $1 where rowid=$rowid and owner=\"$user\""
2351 return
2352 fi
2353 fi
2354 cat $2 \
2355 | (cols=""
2356 while IFS=: read prompt name type args; do
2357 [ x"$name" = x"stage" ] && continue
2358 if [ -n "$rowid" ]; then
2359 val=`getpar $name|sed -e 's/\"/\"\"/g'`
2360 sq $db "update $1 set $name=\"$val\" where rowid=$rowid and owner=\"$user\""
2361 else
2362 eav=$eav${eav+,}" max(case var when '$name' then val end)"
2363 fi
2364 done
2365 [ -n "$rowid" ] && return
2366 cond="where sessid='$session' group by sessid"
2367 sq $db "replace into $1 select $eav,\"$user\" from par $cond"
2368 # Think over again about putting $user
2371 genform() {
2372 # $1 = form definition file
2373 # $2, $3 (optional)= table name and ROWID
2374 # If $GF_VIEWONLY set and nonNull, output values without form
2375 # If $GF_HIDDEN set, use it hidden values
2376 # If $GF_OWNER set, use it as value of name="owner"
2377 # If $GF_STAGE set, use it as value of name="stage"
2378 forms="" hiddens="" rowid=$3
2379 if [ ! -e "$1" ]; then
2380 echo "そのようなデータベースはないようです($2)。" | html p
2381 return
2382 elif [ -n "$2" ]; then
2383 err genform1: "select * from $2 where rowid='$rowid'"
2384 rec=`query "select * from $2 where rowid='$rowid';"`
2385 if [ -z "$rec" ]; then
2386 pk=`gettblpkey $2`
2387 ###rec=`sq $db "select rowid from $2 where $pk='$rowid'"`
2388 err "select rowid from $2 where $pk='$rowid';"
2389 rec=`query "select rowid from $2 where $pk='$rowid';"`
2390 err rec-rowid=$rec
2391 rowid=$rec
2392 rec=$3
2393 fi
2394 if [ -z "$rec" ]; then
2395 echo "そんなレコードはないみたいね..." | html p
2396 return
2397 fi
2398 fi
2399 if [ -z "$GF_VIEWONLY" ]; then
2400 rm='<input id="rm" name="rm" type="checkbox"
2401 value="yes"><label for="rm">このエントリの削除</label>
2402 <span>ほんとうに消しますよ(確認)!
2403 <input name="confirm" type=checkbox value="yes">はい</span>'
2404 fi
2405 # Image Cache dir
2406 err genform: getcache=$2/$rowid
2407 td=`getcachedir "$2/$rowid"`
2408 while IFS=: read prompt name keytype type args; do
2409 [ -z "${prompt%%\#*}" ] && continue # skip comment line(#)
2410 sp="${args:+ }"
2411 form="" val=""
2412 if [ -n "$rowid" ]; then
2413 # err genform2a: Seeking for "$2.$name, type=$type"
2414 val=`getvalbyid $2 $name $rowid $td`
2415 err genform3a: getvalbyid $2 $name $rowid $td
2416 err genform3b: val="[$val]"
2417 fi
2418 if [ -n "$GF_VIEWONLY" ]; then
2419 is_hidden "$2" "$name" && continue
2420 fi
2421 case "$type" in
2422 text*)
2423 cgiform=cgi_multi_$type
2424 if [ -s $td/$name.count -a -n "$val" ]; then
2425 form=`$cgiform $name $td`
2426 val=$(echo "$val"|
2427 while read fn; do
2428 echo "<tr><td>`cat $td/$fn`</td></tr>$nl"
2429 done)
2430 val="<table>$nl$val$nl</table>"
2431 else
2432 #form="<input name=\"$name\" value=\"$val\" type=\"$type\"$sp$args>$nl"
2433 err genform: cgi_$type $name $val "$args"
2434 form=`cgi_$type $name "$val" "$args"`
2435 fi
2436 ;;
2437 [Rr][Aa][Dd][Ii][Oo])
2438 fh="<label><input type=\"radio\" name=\"$name\""
2439 form="`echo $args|sed -e \
2440 \"s,\([^ =][^=]*\)=\([^= ][^= ]*\),$fh value=\\"\2\\">\1</label>,g\"`"
2441 ;;
2442 [Cc][Hh][Ee][Cc][Kk][Bb][Oo][Xx])
2443 form="<label><input type=\"checkbox\" name=\"$name\" value=\"${args#*=}\">${args%=*}</label>"
2444 ;;
2445 [Ss][Ee][Ll][Ee][Cc][Tt])
2446 fh="<select name=\"$name\">$nl"
2447 form=$(for l in $args; do
2448 echo "<option value=\"${l#*=}\">${l%=*}</option>"
2449 done)
2450 if [ -n "$val" ]; then
2451 form=`echo $form|sed -e "s,\(value=.$val.\),\\1 selected,"`
2452 fi
2453 form="$fh$form</select>"
2454 ;;
2455 [Ii][Mm][Aa][Gg][Ee]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Bb]inary)
2456 if [ -s $td/$name.count ]; then
2457 form=`cgi_multi_file $name $td "$args"`
2458 if [ -n "$val" ]; then
2459 hrfb="$myname?showattc+$2_m"
2460 val=$(echo "$val" \
2461 | while read fn; do
2462 data=`percenthex $td/$fn`
2463 #ct=`cat $td/$fn.content-type`
2464 ct=`file --mime-type $td/$fn|cut -d' ' -f2`
2465 ri=`cat $td/$fn.rowid`
2466 ## err fn=$fn, name=$name, ri=$ri; ls -lF $td 1>&3
2467 #imgsrc="<img src=\"data:$ct,$data\">"
2468 #echo "<a href=\"$hrfb+$ri\">$imgsrc</a><br>"
2469 iconhref $td/$fn "$hrfb+$ri" ""
2470 done)
2471 fi
2472 else
2473 form="<input type=\"file\" name=\"$name\" $args>"
2474 if [ -n "$val" ]; then
2475 imgs=$(echo "$val"\
2476 |while read fn;do
2477 data=`percenthex $td/$fn`
2478 echo "<img src=\"data:image/png,$data\">$fn<br>"
2479 done)
2480 form=$form"<br>$imgs"
2481 val=$imgs # 2015-06-15
2482 else
2483 form="<input type=\"file\" name=\"$name\" $args>"
2484 fi
2485 fi
2486 ;;
2487 [Hh][Ii][Dd][Dd][Ee][Nn])
2488 if [ -n "$GF_STAGE" -a x"$name" = x"stage" ]; then
2489 args="value=\"$GF_STAGE\""
2490 fi
2491 form="<input type=\"hidden\" name=\"$name\" $args>"
2492 prompt='' # Remove prompt
2493 ;;
2494 [Aa][Uu][Tt][Hh][Oo][Rr])
2495 form="<input type=\"hidden\" name=\"author\" value=\"$user\">"
2496 prompt="" ;;
2497 [Oo][Ww][Nn][Ee][Rr])
2498 val=${GF_OWNER:-$val}
2499 val=${val:-$user}
2500 form="<input type=\"hidden\" name=\"owner\" value=\"$val\">"
2501 prompt="" ;;
2502 [Uu][Ss][Ee][Rr])
2503 # XXX: is null $user ok?
2504 #form="<input type=\"hidden\" name=\"user\" value=\"$user\">"
2505 [ -n "$GF_VIEWONLY" ] && continue
2506 form="$user"
2507 ;;
2508 [Pp]assword)
2509 [ -n "$GF_VIEWONLY" ] && continue
2510 form="`cgi_passwd`"
2511 val=""
2512 ;;
2513 [Ss][Ee][Rr][Ii][Aa][Ll]|[Ss][Tt][Aa][Mm][Pp])
2514 if [ -z "$rowid" ]; then
2515 val=$((($(date +%s)-1433084400)/10))c$$
2516 fi
2517 ## form="<input type=\"hidden\" name=\"serial\" value=\"$val\">"
2518 ## 2015-07-31
2519 form="<input type=\"hidden\" name=\"$name\" value=\"$val\">"
2520 prompt="" ;;
2521 [Ss][Ee][Ss][Ss][Ii][Oo][Nn])
2522 prompt=""
2523 ;;
2524 parent|path|blog*)
2525 prompt=""
2526 ;;
2527 "*"*)
2528 tail=$tail"``"
2529 continue ;;
2530 esac
2531 if [ -n "$prompt" ]; then
2532 if [ -n "${GF_VIEWONLY}" ]; then
2533 form=$val
2534 else
2536 fi
2537 forms=$forms" <tr class=\"$name\"><th>$prompt</th><td>$form</td></tr>$nl"
2538 else
2539 hiddens=$hiddens$nl"$form"
2540 fi
2541 done < $1
2542 # enctype="multipart/form-data"
2543 cat<<EOF
2544 <form action="${GF_ACTION:-$myname}" method="POST" enctype="multipart/form-data">
2545 ${rowid:+$rm}
2546 <table class="b $2">
2547 $forms
2548 </table>$hiddens
2549 ${GF_STAGE:+`cgi_hidden stage $GF_STAGE`}
2550 ${rowid:+<input type="hidden" name="rowid" value="$rowid">}
2551 EOF
2552 if [ -z $GF_VIEWONLY ]; then
2553 cat<<EOF
2554 <input type="submit" name="sub" value="OK">
2555 <input type="reset" name="res" value="Reset">
2556 EOF
2557 fi
2558 cat<<EOF
2559 </form>
2560 $tail
2561 EOF
2563 edittable() {
2564 # $1=form-def $2=table $3 rowid
2565 genform "$@"
2567 viewtable() {
2568 GF_VIEWONLY=1 genform "$@"
2570 showattc() {
2571 # $1=table_m $2=rowid
2572 err \$1=$1 \$2=$2
2573 if ! isfilereadable $user $1 $2; then
2574 contenttype; echo
2575 echo "このファイルは管理者のみしか見られません" | html p
2576 putfooter; exit
2577 fi
2578 idir=`umask 002; mktempd` || exit 1
2579 # tmpfiles=$tmpfiles"${tmpfiles+ }$idir"
2580 bin=$idir/$myname-$$.bin
2581 sql="select quote(bin) from $1 where rowid='$2';"
2582 err showattc: sql: $sql
2583 sq $db "$sql" | unhexize > $bin
2584 tv=`query "select type,val from $1 where rowid='$2';"`
2585 type=${tv%\|*} fn=${tv#*\|}
2586 err tv=$tv type=$type fn=$fn, tp2=${tv%\|*}
2587 ct=${type#file:}
2588 case $ct in # all text/* changed to text/plain
2589 text/*)
2590 charset=`nkf -g $bin|cut -d' ' -f1`
2591 case $charset in
2592 ASCII*) charset="" ;;
2593 esac
2594 ct="text/plain${charset:+; charset=$charset}"
2595 ;;
2596 esac
2597 contenttype "$ct"
2598 echo "Content-Disposition: filename=\"$fn\""
2599 echo "Content-Length: " `cat $bin | wc -c`; echo
2600 #echo "Content-Type: " ${type#file:}; echo
2601 cat $bin
2604 # Some default stupid handler on CGI values
2606 default_storedb() {
2607 # ARG: $1=table-def-file
2608 # RET: $tbl=table-name, $col=mail-column, $cols=columns
2609 tbl=`basename $1`
2610 tbl=${tbl%.def}
2611 cols="`grep :text $1|cut -d: -f2`"
2612 col=`echo "$cols"|head -1`
2613 vcol=`getpar $col`
2614 err default0: \$1=$1 col=$col cols="[$cols]" vcol=$vcol
2615 if [ -n "$vcol" ]; then
2616 par2table $1
2617 else
2618 return 2 # No insertion occurred
2619 fi
2622 default_view() { # $1=def-file
2623 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
2624 ## DT_VIEW="edittable+$tbl" dumptable html $tbl "name memo file" \
2625 default_storedb "$@"
2626 query "select rowid from $tbl order by rowid desc;" \
2627 | while read rowid; do
2628 viewtable $1 $tbl $rowid
2629 done | m4 -D_TITLE_="$tbl" \
2630 -D_FORM_="`genform $1`" \
2631 -D_DUMPTABLE_="syscmd(cat)" \
2632 $layout/html.m4.html $layout/form+dump.m4.html
2634 default_viewtext() { # $1=def-file
2635 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
2636 default_storedb "$@"
2637 DT_VIEW="viewtable+$tbl" dumptable html $tbl "name memo file" \
2638 | m4 -D_TITLE_="$tbl" \
2639 -D_FORM_="`genform $1`" \
2640 -D_DUMPTABLE_="syscmd(cat)" \
2641 $layout/html.m4.html $layout/form+dump.m4.html
2643 default_smail() {
2644 default_storedb "$@"
2645 if [ $? -eq 2 ]; then
2646 m4 -D_TITLE_="入力" \
2647 -D_FORM_="`genform $1`" \
2648 -D_DUMPTABLE_="" \
2649 $layout/html.m4.html $layout/form+dump.m4.html
2650 return
2651 fi
2652 cond=""
2653 for pk in `gettblpkey $tbl`; do
2654 pv=$(sqlquote $(getpar $pk))
2655 cond="$cond${cond:+ and }$pk=$pv"
2656 done
2657 sql="select rowid from $tbl where $cond;"
2658 rowid=`query "$sql"`
2659 err smail1 - "$sql" "-> rowid=$rowid"
2661 while IFS=: read prompt name keytype type args; do # Read from $1
2662 val=`getpar $name`
2663 if [ -n "$val" ]; then
2664 text="$text
2665 $prompt
2666 $name=$val
2667 ---------------------------------------------------------"
2668 fi
2669 case "$type" in
2670 image|document|file)
2671 fn="`getvalbyid $tbl $name $rowid $tmpd`"
2672 fns=$(echo "$fn"|while read fn; do
2673 err mv $tmpd/$fn.orig $tmpd/$fn
2674 mv $tmpd/$fn.orig $tmpd/$fn
2675 rm $tmpd/$fn.rowid # Remove cache flag
2676 err "`ls $tmpd/$fn`"
2677 echo $fn
2678 done)
2679 files="$files $fns"
2680 ;;
2681 esac
2682 done < $1
2683 err FILES=$files "`ls -lF $tmpd`"
2684 subj="from ${REMOTE_ADDR}"
2685 (echo "$url"
2686 echo "への書き込みがありました。"
2687 echo "------"
2688 echo "$text"
2689 ) | (cd $tmpd &&
2690 err LS="`ls -lF`" &&
2691 $mydir/sendmultipart.sh -t "$admin" -s "$subj" $files)
2692 m4 -D_TITLE_="入力完了" $layout/html.m4.html
2693 echo "以下の内容で送信しました。" | html p
2694 viewtable $1 $tbl \
2695 `query "select rowid from $tbl order by rowid desc limit 1;"`
2696 echo "戻る" | html a "href=\"?\""