s4

view s4-funcs.sh @ 149:0e28561bf73a

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