s4

view s4-funcs.sh @ 127:c17964aa7715

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