s4

view s4-funcs.sh @ 393:cee8ffb43ae2

Revert to direct retrieving from db
author HIROSE Yuuji <yuuji@gentei.org>
date Mon, 05 Dec 2016 13:57:22 +0859
parents be955399aec9
children f095e97066c5
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=22
26 #thumbxy=120x120
27 thumbxy=96x96
28 iconxy_S=80x80
29 iconxy_M=400x400
30 maximagexy=1600x1600
31 ### maximagexy=400x400
32 file_accept='accept="image/*,text/*,audio/*,application/vnd.oasis.*,application/pdf,application/x-*"'
33 blogreadflagrowid=0
34 querylog=$tmpdir/query.log
36 tconfs=""
37 imgcached=cache/img.`date +%Y/%m`
38 conftbl=_tblconf
39 nl="
40 "
41 iconcachekey="profimgcache_S"
42 case "$HTTP_USER_AGENT" in
43 *i[Pp]hone*|*[Aa]ndroid*) touchpanel=1 ;;
44 *) touchpanel="" ;;
45 esac
46 . ./s4-cgi.sh
48 : <<EOF
50 !! 検索等でblogテーブル参照時は sql4readableblogs() で定義される
51 !! readableblogs テーブルを使うこと
52 資料配布、グループ管理・ML、ファイル交換、クリッカー、アンケート
53 レポート提出管理
54 ひとつのarticleをheadingにして新規ツリーを作成、あるといいかも。
56 [2016]
57 7/12 根本への反省
58 * cgi自身の $1, $2 での切り替えでなく、CGI変数での受け渡しにすべき。
59 arg1/arg2/arg3 的に $1 に / 区切りでつけた方がよかったかな。
61 [以下2015]
62 8/4 ○グループに承認加入モードを追加
63 ○グループに参加していない場合は grpaction できない
64 Web
65 締切設定
67 8/2 ○s4.cgi生成系 → index.cgi生成
68 ○自分の提出物リスト
70 7/19 ○設置
71 ○一斉送信
72 ○getparfilename の tmpd の扱い
73 ○やっぱりs4にしようかな
74 7/18 ○書込著者からホームへのリンク
75 7/17 ○個人blogに「レポート提出用」がついたときの挙動
76 ○添付ファイル回収
77 ○imgcacheは別ディレクトリにしないと + .htaccess
78 7/15 ○レポート提出モードの表示を付ける
79 管理者権限での削除? → まだいいか
81 7/13 ○前回アクセス基準の新着数は欲しいなあ
82 ○レポート提出はどうしよう
83 → ○blogにモードを追加:
84 ○レポート提出モード
85 添付ファイル (誰が見たかログ)
86 クリッカーは別立てメニューにしないと(管理者がON/OFF)
87 ○添付ファイルの読み出し権(6/22から) ← モードで対処
90 7/9 ○管理者の追加
91 △グループメンバの操作 → 要不要を吟味
92 ○グループ情報編集の行先はそのグループがいい?
93 ○新規グループの作成はどこから入るか
94 △グループホームとユーザホームを揃える
96 7/8 ○グループ一覧をユーザ一覧と揃える。
98 7/6の次 ○グループのconf編集の入口
99 ○グループ検索
101 6/22の次 ○ホーム画面、○招待状、親記事追跡、○編集ボタン、削除ボタン、
104 6/7の次 ○blogを作ってみる || userconfig || _mのまとめ編集(削除)
105 6/7の次の次 ○userconfigの画面だけ作ってみる。
107 ○ 5/28の次 edittableに「削除」ボタンを足す
108 ○6/1 par2tableを triplex 対応に
109 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'));
110 →とすると 一気に
112 ## form.def を考えなおそう:
113 ## userのように必須カラムを決まった位置に付ける?
114 ## 必須カラム、owner(foreign key passwd(name)), update datetime
115 ## ユーザ管理とグループ管理はデフォルトで持たせてしまえ
117 ## 縦持ちデータの入力/編集を供給する関数 single + multi
118 ## 持てるテーブル構造はシステム標準5種 + ユーザ定義2種類
119 ## 1. passwd
120 ## 2. grp
121 ## 3. grp_mem
122 ## 4. topic 記事のIDとなる
123 ## 5. topic_cont 特定IDの記事の内容物
124 ## 6. list 繰り返し登場あり
125 ## 7. hash 繰り返し登場なし
127 ## ● listの定義:
128 ## create table list(id unique, parentID, type, value);
129 ## ● hashの定義:
130 ## create table hash(parentID, type, value, primary key(parentID, type));
132 ## グループ属性: community, friend
133 ## ○ blob使えるのかな。streamで行けるのか? xxdで行けた。ありがたい。
134 ## form-defとtableは1対1対応でいいか
135 ## csv2sq3 で .csv.sq3 の Makefile
137 ## 書き込みオブジェクトとは何か?
138 ## topic : id, belongto, title, owner, mode
139 ## type := root | comment
140 ## topic_cont : id, topicid(F), ppath, contenttype, filename, content,
141 ## unique(id, filename)
142 ## type := body(single) | attachment(multi)
144 ## group := name(P), tag, gecos, owner(F), mode
145 ## tag := personal | friend | ... any string
146 ## group_member := gname(F), type, name(F), UNIQUE(gname, type, name)
147 ## type := "u" | "g"
148 ## できたー!
149 ## 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';
150
151 ↓以下に変更
152 with recursive allmem as
153 (select gname,val from grp_m where gname='foo'
154 union all select grp_m.gname,grp_m.val from
155 grp_m,allmem where allmem.val=grp_m.gname)
156 select val from allmem where val in (select name from user);
159 with recursive allmem as
160 (select gname,val from grp_m where gname='foo'
161 union all select grp_m.gname,grp_m.val from grp_m,allmem
162 where allmem.val=grp_m.gname)
163 select a.*, coalesce(b.val,a.val) from allmem a left join grp_mem_s b
164 on a.gname=b.gname and a.val=b.user and b.key='email'
165 where a.val in (select name from user);
168 ## triggerもできた。
169 ## 5/22から:グループ作成画面
170 ## 埋め込み画像 data:CONTENT-TYPE;base64,.....
172 ## 考え得るノードタイプ
173 ## 日報 - 個人所属かグループ所属か
174 ## 課題提出 - 個人所属かグループ所属か
175 ## グループ管理
176 ## 個人情報管理
177 ##
179 ## 例: group:sip - topic:1:sip:Aperture:yuuji:rw
180 ## - topic:2:sip:ISO:yuuji:rw
181 ## topic_cont 1:1:/:body:text...Aperture
182 ## 2:1:/1:body:text..Aperture
183 ## 3:1:/1:attachment:binary..Aperture
184 ## 4:1:/2:body:text..Aperture
185 ## 5:1:/2:attachment:binary..Aperture
186 ## 6:2:/:body:text..ISO
187 ## 7:2:/6:body:text..ISO
188 ## 8:2:/6:attachment:binary..
190 ## ログテーブル
191 ## time, who, action, tbl, id idなんか取れるかな
195 ■表設計
196 * 3つの表に分散管理
197 id格納表 + hash表 + list表
198 * *_s *_m
202 user, user_map, user_col
204 ■抽象エントリタイプ
205 * user
206 idとして機能 → table中の owner に自動挿入(?)
207 * group
208 権限判定に利用
209 * serial
210 自動idとして機能
211 * password
212 入力 type=passwordで入力
213 変更 oldpasswd, password×2 で確認後修正
214 * session
215 password認証後のセッションキーとして機能
216 * text
217 入力 type=text
218 * textarea
219 入力 textarea
220 * image|document
221 入力 type=fileで入力し、mime-typeを確認
222 * owner
223 入力時の $user で、外部キー制約が付く
224 * gowner
225 グループとしての所有者で、外部キー制約が付く
226 * timestamp
227 datetime()
228 * parent
229 木構造の場合の親の位置
230 * path
231 木構造の場合の自分の位置
233 格納タイプ
234 * list
235 表 parentID, key, val でUNIQUE(parentID, key, val)
236 * hash
237 表 parentID, key, val でUNIQUE(parentID, key)
239 オブジェクトタイプ
240 * entry
241 id, title, owner
242 * textpart
243 id, parentID, text
244 * binarypart
245 id, parentID, contenttype, filename, content
246 * content
247 hash(textpart), list(binarypart)
248 * topic
249 id, hash(content), list(reply)
250 * reply
251 id, parentID, content
252 * blog
253 list(entry)
254 blog = [topic, list(reply)]
257 blog = [ {"title" => "hoge", "owner" => "yuuji", "date" => "2015-04-27",
258 "text" => "hogehoge ..",
259 "reply" => [ {"serial" => 1,
260 "author" => "taro",
261 "date" => "2015-04-28",
262 "parent" => "/",
263 "path" => "/1",
264 "text" => "blah, blah, ....",
265 "image" => ["a.jpg", "b.jpg"] },
266 {"serial" => 2,
267 "author" => "hanako",
268 "date" => "2015-04-29",
269 "parent" => "/",
270 "path" => "/2",
271 "text" => "blah, blah, ....",
272 "image" => [] }]},
273 {"title" => "buha", ...} ]
276 user:=
277 ユーザ名(英数字):name:p:text:length="20" maxlength="40"
278 パスワード:pswd:s:password:length="20" maxlength="40"
279 説明(日本語OK):gecos:s:text:length="20" maxlength="40"
280 セッションキー:skey:s:session
281 メイルアドレス:email:m:text:length="20" maxlength="40"
282 住所:address:m:textarea:maxlength="400"
283 プロフィール画像:profimg:m:image:maxlength="400K"
284 履歴書:profpdf:m:document:maxlength="4M"
286 変換表
287 /user/email=m
289 blog:=
290 シリアル:id:p:serial
291 タイトル:title:s:text:
292 所有者:owner:s:owner:
293 時刻:ctime:s:stamp:
294 リード文:heading:s:textarea:
295 リプライ:reply:m:*article:
297 article:=
298 シリアル:id:p:serial
299 筆者:author:s:owner
300 時刻:ctime:s:stamp:
301 参照元:parent:s:parent:
302 パス:path:s:path:
303 本文:text:s:textarea:
304 画像:image:m:image:
306 履歴書:profpdf:m:document:maxlength="4M"
309 EOF
311 sq() {
312 # ./args.rb -cmd ".timeout 3000" "$@"
313 sqlite3 -cmd 'PRAGMA foreign_keys=ON' -cmd ".timeout 3000" "$@"
314 }
315 dbsetup() {
316 [ -d $tmpdir ] || mkdir -m 1777 $tmpdir
317 [ -d $dbdir ] || mkdir -m 1775 $dbdir
318 sqi=$tmpdir/sqi.$$
319 sqo=$tmpdir/sqo.$$
320 mkfifo $sqi $sqo
321 #tail -f $sqi | sq $db & # "tail -f" is too heavy. DO NOT USE!!
322 sq $db < $sqi &
323 sq3pid="`jobs -p` $!"
324 exec 2>> $tmpdir/error.out
325 exec 3>> $tmpdir/debug.out
326 exec 5> $sqi # Turning $sqi access through fd5 for continuous open state
327 rm $sqi
328 }
329 cleanup() {
330 trap '' INT HUP EXIT TERM PIPE
331 echo .quit >&5
332 kill $sq3pid
333 kill $sq3pid
334 rm -f $sqo $sqi
335 rm -rf $tmpfiles
336 }
337 # We want to use piped function to put querylog, but we use
338 # simple redirection for the sake of speed.
339 query() {
340 echo ".once $sqo" >&5
341 echo "`date '+%F %T'`:[${user:-NULL}] <<<" >> $querylog
342 if [ -z "$1" ]; then
343 tee -a $querylog
344 else
345 echo "$@" >> $querylog
346 echo "$@"
347 fi >&5
348 cat $sqo
349 echo '>>>' >> $querylog
350 }
351 _m4() {
352 #_S4NAME_=f,f,f
353 m4 ${_S4NAME_:+"-D_S4NAME_=${_S4NAME_}"} "$@"
354 }
355 ismember() {
356 # $1=user, $2=group
357 err ismem: "select user from grp_mem where gname=$(sqlquote $2) and user='$1';"
358 test -n "`query \"select user from grp_mem where gname=$(sqlquote $2) and user='$1';\"`"
359 }
360 isuser() { # Check if $1 is a valid user
361 test -n "`query \"select name from user where name='$1';\"`"
362 }
363 isgroup() { # Check if $1 is a valid group
364 err isgroup: "select gname from grp where gname=$(sqlquote $1);"
365 test -n "`query \"select gname from grp where gname=$(sqlquote $1);\"`"
366 }
367 isgrpowner() (
368 # $1=user, $2=group
369 gn=`sqlquote "$2"`
370 sql="select user from grp_adm where gname=$gn and user='$1';"
371 err isgrpowner: $sql
372 test -n "`query $sql`"
373 )
374 getgroupadminmails() {
375 # $1=group
376 for i in $(getgroupadmins $1); do
377 email4group "$1" "$i" ;
378 done
379 }
380 getgroupadmins() { # $1=group
381 # This function is called in a backquote, so needn't to be subshellized
382 qgrp=`sqlquote "$1"`
383 query "select user from grp_adm where gname=$qgrp;"
384 }
385 getgroupattr() { # $1=group $2=attr
386 # This function is called in a backquote, so needn't to be subshellized
387 getvalbyid grp $2 \
388 $(query "select rowid from grp where gname=`sqlquote $1`;")
389 }
390 getgroupbyid() {
391 # $1=id|gname
392 sql="select coalesce((select gname from grp where gname=$(sqlquote $1)),
393 (select gname from grp where rowid=$(sqlquote $1)));"
394 # err ggbyid: `echo $sql`
395 query $sql
396 }
397 isfilereadable() { # $1=user $2=tbl $3=rowid
398 # Return true if user($1) can read attachment files in tbl($2):rowid($3)
399 [ -z "$1" -o -z "$2" -o -z "$3" ] && return 1 # invalid argument
401 # Return true when anonymous mode
402 [ "$anonymousmode" ] && return 0
403 # case `getvalbyid blog mode $2` in
404 # normal|*open*|"") return 0 ;;
405 # *closed*)
406 # owner=`getvalbyid blog owner $2`
407 # if isgrp $owner; then
408 # isgrpowner $1 $owner && return 0 || return 1
409 # elif isuser $owner; then
410 # [ x"$1" = x"$owner" ] && return 0 || return 1
411 # fi
412 # esac
413 # ↑ 要はこういう処理を↓で一気にやっている
414 sql="with getblog as (\
415 select key,val from blog_s where id=(\
416 select blogid from article where id in\
417 (select id from $2 where rowid=$3))),\
418 getowner as (select val from getblog where key='owner'),\
419 getmode as (select val from getblog where key='mode')\
420 select case\
421 when (select author from article where\
422 id=(select id from $2 where rowid=$3))='$1' \
423 then 'author'\
424 when (select val from getmode) in ('report-open', 'normal')\
425 then 'open'\
426 when (select val from getmode) is null \
427 then 'open'
428 when (select val from getowner) in (select gname from grp)\
429 then (select user from grp_adm where \
430 gname=(select val from getowner) and \
431 user='$1')\
432 when (select author from article where\
433 id=(select id from $2 where rowid=$3))='$1'
434 then 'user+author'
435 else '' end;"
436 ## err isfilereadable: sql="`echo $sql`"
437 # caseのネストで内側のcaseがスカラーtrueを返しても外側はtrue扱いにならない
438 result=`query "$sql"`
439 [ -n "$result" ] && return 0
440 return 2
441 }
442 linkhome() {
443 # $1=UserOrGroup
444 echo -n '<a href="?'
445 if isuser $1; then
446 err "select 'home+'||rowid from user where name='$1';"
447 query "select 'home+'||rowid from user where name='$1';"
448 else
449 echo -n "grp+$1"
450 fi
451 echo "\">`gecos $1`</a>"
452 }
453 hreflink() {
454 # s4 specific notation:
455 # ^href=URL
456 # ^iframe=URL
457 # OSM umap Wikistyle Notation:
458 # [[URL]] - Simle Link
459 # [[URL|Word]] - Link with anchor word
460 # {{URL}} - <img src="URL">
461 # {{URL|width}} - <img src="URL" width="width">
462 # {{{URL}} } - <iframe src="URL"></iframe>
463 # {{{URL|height}} - <iframe src="URL" height="height"></iframe>
464 _hrefptn="[-A-Za-z0-9,.:;/~_%#&+?=@!]*"
465 sed -e "s|\[\[\($_hrefptn\)\|\(.*\)\]\]|<a href=\"\1\">\2</a>|g" \
466 -e "s|\[\[\($_hrefptn\)\]\]|<a href=\"\1\">\1</a>|" \
467 -e "s|{{{\($_hrefptn\)\|\(.*\)}}}|<iframe src=\"\1\" height=\"\2\"></iframe>|g" \
468 -e "s|{{{\($_hrefptn\)}}}|<iframe src=\"\1\"></iframe>|g" \
469 -e "s|{{\($_hrefptn\)\|\(.*\)}}|<img src=\"\1\" width=\"\2\">|g" \
470 -e "s|{{\($_hrefptn\)}}|<img src=\"\1\">|g"\
471 -e "s|^href=\($_hrefptn\)|<a &>\1</a>|" \
472 -e "s|^iframe=\($_hrefptn\)|<iframe src=\"\1\"></iframe>|"
473 }
474 minitbl() {
475 sed -n '
476 /^|.*|/ {; # If the line begin with "|" and has 2 or more "|"
477 s,|$,,; # Remove trailing "|" first
478 s,|\* *\([^|]*\) *,<th>\1</th>,g; # "|*..." to "<th>...</th>"
479 s,| *\([^|]*\) *,<td>\1</td>,g; # "|..." to "<td>...</td>"
480 s,^,<tr>,; s,$,</tr>,; # Enclose with "<tr>" and "</tr>"
481 H; # Concat this line to HoldSpace
482 s/.*//; # Delete PatternSpace for finalization
483 $ b cont
484 d; # If in final line, output the rest, else jump to next turn
485 }
486 :cont
487 x; # For non-"|" lines, check HoldSpace
488 /^./ {; # If HoldSpace has "|" table elements
489 s|^|<table class="mini">|; # Enclose whole elements like this:
490 # s|$|</table>|; # <table class="mini">..\n..</table>
491 p; # Print whole "table" element
492 s/.*//; # Erase all when done.
493 x; s|^|</table>|; x; # Preppend /table to the next line
494 }
495 x; # Back to the newest line
496 p; # Print rest'
497 }
498 acclog() (
499 # $1=table, $2=rowid
500 n=${2%%[!0-9]*} # Remove non-digit chars from $2(should be rowid)
501 if [ -n "$n" ]; then
502 now=`date +"%F %T"`
503 #query "replace into acclog values('$user', '$1', '$n', '$now');"
504 #query "replace into acclog values('$user', '$1', $n, '$now');"
505 query "replace into tblaccesses values('$user', '$1', $n, '$now');"
506 fi
507 )
508 gecos() (
509 u=`sqlquote ${1:-$user}`
510 query "select gecos from gecoses where name=$u;"
511 )
512 setpar() {
513 query "replace into par values('$session', '$1', '$2', \"$3\");"
514 }
515 replpar() {
516 query "update par set val=\"$3\" where sessid='$session' and var='$1' and type='$2';"
517 }
518 getpar() {
519 val=`query "select val from par where var='$1' and sessid='$session' $2;"`
520 ## err getpar/val1: "val=[$val]"
521 if [ -z "$val" ]; then
522 val=`query "select val from cookie where var='$1' and sessid='$session' $2;"`
523 fi
524 ## err getpar/val2: "val=[$val]"
525 case "$var" in
526 owner)
527 if [ x"$user" = x"$val" ]; then
528 echo $user; return
529 elif ismember $user $val; then
530 echo $val; return
531 fi ;;
532 esac
533 ## err getpar/ret: "val=[$val]"
534 echo "$val"
535 }
537 getpartype() {
538 query "select type from par where var='$1' and sessid='$session' $2;"
539 }
540 getparcount() {
541 query "select count(*) from par where var='$1' and sessid='$session' $2;"
542 }
543 getparfilename() {
544 # null if type of $1 is not file
545 (f=`query "select val from par where var='$1' and sessid='$session' and type='file' $2;"`
546 [ -n "$f" ] && echo $f)
547 }
548 sqlquote() {
549 (v="$1"
550 case "$v" in
551 "") return ;; # null
552 "X'"*) # quoted hex string
553 echo $1 ;;
554 *\"*) # string including dbl-quote"
555 v=`echo "$v"|sed -e 's/\"/\"\"/g'`
556 echo "\"$v\""
557 return ;;
558 *.*.*|*-*-*|*[Ee]*[Ee]*|[Ee]*|*[\ -,:-df-~]*) # string
559 echo "\"$v\""
560 return ;;
561 *)
562 if expr "$v" : '[-0-9.Ee][-0-9.Ee]*$' >/dev/null 2>&1; then
563 echo $v # MAYBE numeric, maybe...
564 else
565 echo "\"$v\""
566 fi ;;
567 esac)
568 }
569 sqlquotestr() (
570 case "$1" in
571 *\'*) v=`echo "$1"| sed "s/'/''/g"`
572 echo "'$v'" ;;
573 *) echo "'$1'" ;;
574 esac
575 )
576 mktempd() {
577 TMPDIR=$tmpd mktemp -d -t $session
578 }
579 getcachedir() { # $1=maintable
580 if [ -n "$imgcached" ]; then
581 echo $imgcached/$(echo ${1:-hoge}|md5)/$thumbxy
582 else
583 echo $tmpd/$thumbxy
584 fi
585 }
586 getval() {
587 # $1=table $2=col $3(optional)=condition
588 case `gettbl_coltype "/$1/$2"` in
589 user|author) # author added 2015-06-18 for article(author)
590 echo "$user" ;;
591 stamp|datetime)
592 date "+%F %T" ;;
593 serial)
594 (s=`getpar $2`
595 if [ -n "$s" ]; then echo $s; else echo "`date +%s`x$$"; fi) ;;
596 *)
597 getpar "$2" "$3";;
598 esac
599 }
601 getvalquote() {
602 # $1=table $2=col $3(optional)=condition
603 (v=`getval "$@"`
604 case "$v" in
605 "") echo NULL ;;
606 *) sqlquote "$v" ;;
607 esac)
608 }
609 getparquote() {
610 sqlquote `getpar $1`
611 }
612 getbinbyid() {
613 # $1=tbl $2=col $3=rowid $4=tmpdirForBinary
615 }
616 getvalbyid() {
617 # $1=tbl $2=col $3=rowid $4=tmpdirForBinary
618 # If two or more values found, save them to $tmpd/${column}.$N and
619 # store the number of files into $tmpd/${column}.count and
620 # their each rowid stored into $tmpd/${column}.$N.rowid.
621 ## err gtb-$1=`gettblcols $1`, tbl=$1, col=$2, '$3'=$3
623 (for c in `gettblcols $1`; do
624 if [ x"$2" = x"$c" ]; then
625 ###sq $db "select $2 from $1 where rowid=$3"
626 query "select $2 from $1 where rowid=$3;"
627 return
628 fi
629 done
630 rowid=$3
631 pk=`gettblpkey $1`
632 key=`query "select $pk from $1 where rowid=$3;"`
633 getkey="(select $pk from $1 where rowid=$3)"
634 td=${4:-$tmpd}
635 [ -d $td ] || mkdir -p $td
636 ### err "select $pk from $1 where rowid=$3" - key=$key '$4(tmp)'=$4
637 for kt in s m; do
638 t=${1}_$kt
639 for c in `gettbl_${kt}_cols $1`; do
640 vcount=1 # count(val)
641 if [ x"$2" = x"$c" ]; then
642 #### cond="$t where $pk=\"$key\" and key=\"$c\"" #2015-07-22
643 cond="$t where $pk=$getkey and key=\"$c\""
644 val=`query "select val from $cond limit 1;"`
645 type=`query "select type from $cond limit 1;"`
646 if [ $kt = m ]; then
647 ###vcount=`sq $db "select count(val) from $cond"`
648 # Reset val to store filenames if type is string
649 val=`query "select val from $cond and type like 'file:%' order by rowid;"`
650 err gvb1-sql: "select count(val) from $cond;"
651 vcount=`query "select count(val) from $cond;"`
652 echo $vcount > $td/$c.count
653 i=0
654 ## err gvbid: i=$i vcount=$vcount
655 while [ $i -lt $vcount ]; do
656 slice="order by rowid limit 1 offset $i"
657 i=$((i+1))
658 fn=$c.$i
659 err td=$td, fn=$fn, type=$type, val="[$val]"
660 case $type in
661 file:*)
662 #file=$td/$val
663 r_f=`query "select rowid||'//'||val from $cond $slice;"`
664 f_rid=${r_f%%//*}
665 file=$td/${r_f##*//}
666 # FOR SPEED: Skip file generation if imgcache exists
667 [ -s "$file" -a -s "$td/$fn.rowid" -a -s "$file.rowid" ] \
668 && [ x"$f_rid" = x"`cat $td/$fn.rowid`" ] \
669 && continue
670 # err gvbid-get="select quote(bin) from $cond $slice;"
671 ## err output: "fn=[$fn] file=[$file]"
672 sq $db<<EOF | unhexize > "$file"
673 .output '$td/$fn.rowid'
674 select rowid from $cond $slice;
675 .output '$td/$fn'
676 select val from $cond $slice;
677 .output '$td/${fn}.content-type'
678 select substr(type, 6) from $cond $slice;
679 .output stdout
680 select quote(bin) from $cond $slice;
681 EOF
682 ## err gvbid-get2: "`ls -lF $file`"
683 ## err i=$i - file=$file rowid=`cat $td/$fn.rowid`
684 cp "$td/$fn.rowid" "$file.rowid" 2>&3 # for convenience
685 cp "$file" "$file.orig" 2>&3
686 ls -lh "$file" |
687 awk '{print $5"B"}'|sed 's/BB/B/' > "$file.size"
688 case "$type" in
689 *:[Ii]mage*) mogrify -geometry $thumbxy "$file" ;;
690 ### ここのアイコンを増やしたい
691 *|*:[Aa]pplication*)
692 convert -geometry $thumbxy $imgdir/file-icon.png \
693 png:- > "$file"
694 ;;
695 esac
696 ;;
697 *)
698 sq $db<<EOF
699 .output $td/$fn.rowid
700 select rowid from $cond $slice;
701 .output $td/$fn
702 select val from $cond $slice;
703 EOF
704 val=$val${val:+$nl}"`echo $fn`" # should be delimited by newline
705 ;;
706 esac
707 done
708 else
709 rm -f $td/$c.count
710 case $type in
711 file:*)
712 echo "$val" \
713 | while read fn; do
714 file=$td/$fn
715 if [ ! -s "$file" ]; then
716 ## sq $db "select quote(bin) from $cond and val=\"$fn\"" \
717 query "select quote(bin) from $cond and val=\"$fn\";" \
718 | unhexize > "$file"
719 ##@@## -- echo ${type#file:} > "$file.content-type"
720 case $type in
721 *:[Ii]mage*) mogrify -geometry $thumbxy "$file" ;;
722 *:[Aa]pplication*)
723 convert -geometry $thumbxy $imgdir/file-icon.png \
724 png:- > $file ;;
725 esac
726 fi
727 done
728 ;;
729 esac
730 fi
731 echo "$val" # Keep newlines by ""
732 return
733 fi
734 done
735 done)
736 }
737 getvalbypkey() (
738 # $1=tbl $2=col $3=pkey $4=tmpdirForBinary
739 pk=`gettblpkey $1`
740 rowid=`query "select rowid from $1 where $pk='$3';"`
741 getvalbyid "$1" "$2" $rowid $4
742 )
743 getvalbycond() {
744 # $1=tbl $2=col $3=SQL-Condition
745 ###rowid=`sq $db "select rowid from $1 where $3"`
746 rowid=`query "select rowid from $1 where $3;"`
747 if [ -n "$rowid" ]; then
748 getvalbyid "$1" "$2" $rowid "$4"
749 fi
750 }
751 getpwfield() {
752 # getpwfield user column
753 # val=`sqlite3 $db "select $2 from passwd where name='$1' $3"`
754 val=`getvalbycond user $2 "name='$1'"`
755 if [ -n "$val" ]; then
756 echo "$val"
757 return 0
758 else
759 return 1
760 fi
761 }
762 encode() {
763 if [ -z "$sha1" ]; then
764 if type sha1 >/dev/null 2>&1; then
765 sha1=sha1
766 elif type sha1sum >/dev/null 2>&1; then
767 sha1=sha1sum
768 elif type gsha1sum >/dev/null 2>&1; then
769 sha1=gsha1sum
770 fi
771 fi
772 $sha1 "$@" | cut -d' ' -f1
773 }
774 enjpeg() {
775 if [ -z "$cjpeg" ]; then
776 if type cjpeg >/dev/null 2>&1; then
777 cjpeg="cjpeg"
778 else
779 cjpeg="convert - jpeg:-"
780 fi
781 fi
782 $cjpeg "$@"
783 }
784 mycrypt() (
785 key=$1 salt=$2
786 err \$2=$2
787 case $2 in
788 '$'*'$'*) salt=${salt#\$4\$}
789 salt=${salt%\$*} ;;
790 esac
791 echo -n '$4$'"$salt"'$'
792 echo "$salt$key" | encode || exit 1 # Abort if fail to call encode
793 )
794 hexize() {
795 if [ -z "$hexize" ]; then
796 if type xxd >/dev/null 2>&1; then
797 hexize="xxd -p"
798 else
799 hexize_hd() {
800 hexdump -ve '1/1 "%.2x"'
801 }
802 hexize="hexize_hd"
803 fi
804 fi
805 cat "$@" | $hexize | tr -d '\n'
806 }
807 unhexize() {
808 if [ -z "$unhex" ]; then
809 if type xxd >/dev/null 2>&1; then
810 unhex="xxd -p -r"
811 elif type perl >/dev/null 2>&1; then
812 cat >$tmpd/unhex.pl<<EOF
813 s/([0-9a-f]{2})/print chr hex \$1/gie
814 EOF
815 # Perl refuses -e in setuid circumstances, which can be absurdly
816 # avoided by creating scripts in a file where its parent directory is
817 # world writable...:)
818 unhex="perl -n $tmpd/unhex.pl"
819 fi
820 fi
821 cat "$@" | $unhex
822 # cat $1 | tee /tmp/uh.in| $unhex | tee /tmp/uh.out
823 }
824 percenthex() {
825 hexize "$@" | sed 's/\(..\)/%\1/g'
826 }
827 htmlescape() {
828 sed -e 's/\&/\&amp;/g' -e 's/"/\&quot;/g' -e "s/'/\&apos;/g" \
829 -e "s/</\&lt;/g; s/>/\&gt;/g"
830 }
831 enascii() {
832 if [ -z "$enascii" ]; then
833 if type kakasi >/dev/null 2>&1; then
834 enascii="kakasi -Ha -Ka -Ja -Ea -ka"
835 else
836 enascii_now=`date +%FT%T`
837 enascii_sed() {
838 nkf -Z0Z1Z2 \
839 | sed -e "s/^/$enascii_now/" -e "s|[^-0-9.A-z/,()_=]|x|g"
840 }
841 enascii="enascii_sed"
842 fi
843 fi
844 cat "$@" | $enascii
845 }
846 size_h() {
847 i="$1" oi=$1
848 set -- B B KB MB GB TB
849 while [ $((i)) -gt 9 -a -n "$1" ]; do # -gt 9 means $oi > 1024
850 oi=$i
851 i=$((i/1024))
852 shift
853 done
854 echo ${oi}$1
855 }
856 gettblconf() {
857 if [ -z "$tconfs" ]; then
858 ## tconfs=`sq $db \
859 tconfs=`query \
860 "select tbl||'/'||col||'='||keytype||'/'||objtype from $conftbl;"`
861 fi
862 # /tb1/col1=p/text /tb1/col2=s/text /tb1/col3=m/image /tb2/col1=p/text ...
863 }
864 gettblkeys() {
865 # $1=tbl
866 gettblconf
867 echo "$tconfs" | fgrep "/$1/" | \
868 (type="" keys="" fks="" cols="" scols="" mcols="" hcols=""
869 while IFS='=' read tc conf; do # tc=/tb1/col1 conf=s/text
870 col=${tc##*/} type=${conf%%/*}
871 case $type in
872 *p*)
873 cols=$cols"${cols:+:}$col"
874 keys=$keys"${keys:+:}$col" ;;
875 *f*) cols=$cols"${cols:+:}$col"
876 fks=$fks"${fks:+:}$col" ;;
877 *m*) mcols=$mcols"${mcols:+:}$col" ;;
878 *s*) scols=$scols"${scols:+:}$col" ;;
879 esac
880 case $type in
881 *h*) hcols=$hcols"${hcols:+:}$col" ;;
882 esac
883 done
884 echo "_keys=$keys _fks=$fks _cols=$cols _scols=$scols _mcols=$mcols _hcols=$hcols")
885 }
886 gettblpkey() {
887 # $1=tbl
888 gettblkeys $1 | cut -d ' ' -f 1 | sed -e 's/.*=//' -e 's/:/ /g'
889 }
890 gettblfkey() {
891 (x=`gettblkeys $1`
892 x=${x#*_fks=} # cut before "_fks=" including
893 echo ${x%% *} | tr ':' ' ')
894 }
895 gettblcols() {
896 (x=`gettblkeys $1`
897 x=${x#*_cols=} # cut before "_cols=" including
898 echo ${x%% *} | tr ':' ' ')
899 }
900 gettbl_s_cols() {
901 (x=`gettblkeys $1`
902 x=${x#*_scols=} # cut before "_scols=" including
903 echo ${x%% *} | tr ':' ' ')
904 }
905 gettbl_m_cols() {
906 (x=`gettblkeys $1`
907 x=${x#*_mcols=} # cut before "_mcols=" including
908 echo ${x%% *} | tr ':' ' ')
909 }
910 gettbl_h_cols() {
911 (x=`gettblkeys $1`
912 x=${x#*_hcols=} # cut before "_hcols=" including
913 echo ${x%% *} | tr ':' ' ')
914 }
915 gettbl_coltype() (
916 gettblconf
917 x=`echo "$tconfs"|fgrep $1=`
918 x=${x#*=} # cut before =
919 echo ${x#*/} # cut before p/ including
920 )
921 is_hidden() {
922 # $1=Tbl $2=col
923 gettblconf
924 x=`echo "$tconfs"|fgrep /$1/$2=`
925 x=${x#*=} # cut before =
926 x=${x%%/*} # cut after /
927 case $x in
928 *h*) return 0 ;;
929 *) return 1 ;;
930 esac
931 }
933 dbsetbyid() {
934 # $1=tbl $2=id $3=col $4=val/filename - &optional - $5=content-type
935 (t0=$1 t=$1 p=$2 c=$3
936 tsc=$t/$c val=$4
937 quotedp=$(sqlquotestr "$p")
938 unset primary update
939 gettblconf
940 #err tsc=$tsc, tconfs="$tconfs"
941 conf=`echo "$tconfs"|fgrep "$tsc"=`
942 #err conf=$conf
943 case ${conf#*=} in
944 p*) primary=1 ;;
945 f*) update=1 ;;
946 u*) ;;
947 m*) t=${t}_m;;
948 s*) t=${t}_s;;
949 esac
950 #err t=$t
951 type=string fn=""
952 case $conf in
953 */password)
954 type=encoded ### val=`echo $val|encode`
955 ;;
956 */image*|*/document*)
957 type=`file --mime-type - < "$val" | cut -d' ' -f2`
958 bin="X'`hexize "$val"`'"
959 ;;
960 esac
961 pkey=`echo "$tconfs"|grep "${t0}/.*=p"|sed 1q`
962 pkey=${pkey#/*/} # cut $tbl/
963 pkey=${pkey%=p/*} # cut =p/... -> primary key
964 if [ "$primary" ]; then
965 nulls=`echo "$tconfs"|grep "$t/.*=[fu]/"|sed 's/^.*/, NULL/'|tr -d '\n'`
966 ###sq $db "replace into $t values(\"$val\"$nulls)"
967 query "replace into $t values(\"$val\"$nulls);"
968 elif [ "$update" ]; then
969 query "update $1 set $c=\"$val\" where $pkey=$quotedp;"
970 else
971 query "replace into $t values($quotedp, \"$c\", \"$type\", \"$val\", \"$bin\");"
972 fi
973 )
974 }
975 expire() (
976 at="${1:-$timeout}"
977 FMT="${2:-%F %T}"
978 TZ=GMT gdate -d "$at" +"$FMT"
979 )
980 addsession() {
981 # expireをセット
982 # loginの先にどの画面に行くかの状態遷移表書式を決める
983 expire=`expire ${2:-"+1min"}`
984 query "replace into session values('$1', '$expire');"
985 # Remove old session parameters
986 now=`expire now`
987 query "delete from session where expire < '$now';"
988 }
989 gencookie() (
990 for kv; do
991 expire="`expire '' '%a, %d-%b-%Y %H:%M:%S GMT'`"
992 echo "Set-Cookie: $kv; expires=$expire"
993 done
994 )
995 contenttype() {
996 echo "Content-type: ${1:-text/html; charset=utf-8}"
997 contenttype() {} # Only need to work once
998 }
999 putheader() {
1002 putfooter() {
1003 _m4 -D_TITLE_="${TITLE:-$myname}" $layout/footer.m4.html
1005 getcookie() (
1006 for kv in `echo $HTTP_COOKIE|sed 's/[;, ]/ /g'`; do
1007 k="${kv%%=*}"
1008 v="`echo ${kv#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
1009 query "replace into cookie values('$session', '$k', 'string', \"$v\");"
1010 done
1012 genrandom() {
1013 # $1=columns (default: 10)
1014 dd if=/dev/urandom count=1 2>/dev/null|nkf -MB|fold -w${1:-10}|sed -n 10p
1016 genserial() {
1017 echo $((($(date +%s)-1433084400)/10))c$$
1019 smail() {
1020 # smail rcpts subj (file)
1021 # $SMAIL_TO <- Recipient value of To: header
1022 # $MAIL_FROM <- From: header value
1023 from=`echo "${MAIL_FROM:-$admin}"|nkf -jM|tr -d '\n'`
1024 rcpt=`echo $1` # strip newlines
1025 subj=`echo $2|nkf -jM|tr -d '\n'`
1026 (_m4 -D_RCPT_="${SMAIL_TO:-$rcpt}" -D_SUBJ_="\`$subj'" -D_FROM_="$from" $msgdir/mail-header.m4
1027 cat $3 | nkf -jd ) | sendmail -f $admin $rcpt
1029 setviastring() {
1030 table=$1
1031 oifs="$IFS"
1032 IFS="&"
1033 for us in $2; do
1034 k=${us%%=*}
1035 v="`echo ${us#*=}|tr '%+' '= '|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
1036 query "replace into $table values('$session', '$k', 'string', \"$v\");"
1037 #echo $k=$v
1038 done
1039 IFS="$oifs"
1041 checkdomain() (
1042 # Check the validity of domain by referring DNS
1043 item=$1
1044 err checkdomain $1
1045 host ${item#*@} 1>&3 2>&3
1046 host ${item#*@} >/dev/null 2>&1
1048 pwcheck() {
1049 # $1=passwd
1050 dbpswd=`getpwfield $user pswd`
1051 encpswd=`mycrypt "$1" "$dbpswd"`
1052 ## err user=$user, pswd=$1, db=$dbpswd, enc=$encpswd
1053 [ x"$dbpswd" = x"$encpswd" ]
1055 mypwhash() {
1056 mycrypt `cat` `genrandom 5`
1058 wasureta() {
1059 user=$1
1060 if ! checkdomain $user; then
1061 contenttype; echo
1062 _m4 -D_TITLE_='Invalid email' $layout/title-only.html
1063 echo "ユーザ名($user)には正しいメイルアドレスが必要です。" | html p
1064 putfooter
1065 exit 0
1066 fi
1067 newpswd=`genrandom` # newsalt=`genrandom 5`
1068 #encpswd=`mycrypt "$newpswd" "$newsalt"`
1069 encpswd=`echo $newpswd|mypwhash`
1070 dbsetbyid user $user pswd "$encpswd"
1071 # Avoid $user substitution with m4, because $url comes from user input.
1072 _m4 -D_PSWD_="$newpswd" -D_URL_="$url" -D_ADMIN_="$admin" \
1073 $msgdir/mail-newaccount.m4 \
1074 | sed "s/_USER_/$user/g" \
1075 | smail $user "New Account"
1077 checkauth() {
1078 user=`getpar user`
1079 skc=`getpar skey` # from cookie
1080 [ -z "$user" ] && return 3
1081 skey="`getpwfield $user skey`"
1082 if [ -n "$skey" ]; then
1083 if [ x"$skey" = x"$skc" ]; then
1084 return 0
1085 fi
1086 fi
1087 pswd=`getpar pswd`
1088 quser=`sqlquotestr "$user"`
1089 dbuser=`query "SELECT name FROM user WHERE name=$quser;"`
1090 if [ -z "$dbuser" ]; then
1091 return 1
1092 elif [ x"$pswd" = x"wasureta" ]; then
1093 wasureta $user
1094 return 1 # wasureta error
1095 fi
1096 # dbpswd="`sq $db \"select pswd from passwd where name='$user'\"`"
1097 # putheader; echo; echo user=$user, db=$dbpswd, enc=$encpswd
1098 if pwcheck "$pswd"; then
1099 newsession=`genrandom 50`
1100 dbsetbyid user $user skey "$newsession"
1101 gencookie "user=$user" "skey=$newsession"
1102 return 0
1103 fi
1104 return 2 # Password mismatch
1106 showlogin() {
1107 args=`echo $myargs|tr ' ' '+'`
1108 _m4 -D_SYSNAME_="Welcome" -D_MYNAME_="$myname${args+?}$args" \
1109 $layout/login.m4.html
1110 exit 0
1112 dologin() {
1113 checkauth
1114 st=$?
1115 if [ $st != 0 ]; then
1116 contenttype; echo
1117 _m4 -D_USER_="$user" -D_URL_="$url" -D_ADMIN_="$admin" \
1118 $msgdir/login-fail-$st.m4.html
1119 showlogin # and EXIT
1120 fi
1123 # Do instant jobs here
1124 dbsetup
1125 trap cleanup INT HUP EXIT TERM PIPE
1126 # trap cleanup INT HUP
1128 err() {
1129 echo "$@" 1>&3
1132 cgiinit() {
1133 session=`date +%F-$$`
1134 tmpf=tmp/stream
1135 tmpd=`tmpd=$tmpdir mktempd`
1136 tmpfiles=$tmpfiles" $tmpd"
1137 addsession $session
1138 getcookie
1139 case "$REQUEST_METHOD" in
1140 get|GET) s="$QUERY_STRING" ;;
1141 post|POST) ## dd count=$CONTENT_LENGTH bs=1 of=$tmpf 2>/dev/null #slow
1142 ## dd bs=$CONTENT_LENGTH count=1 of=$tmpf # NOT working
1143 # cat > $tmpf # too much?
1144 head -c $CONTENT_LENGTH > $tmpf # safe?
1145 (echo CL=$CONTENT_LENGTH; ls -lF $tmpf) 1>&3
1146 s="`cat tmp/stream`"
1147 tmpfiles=$tmpfiles"${tmpfiles+ }$tmpf"
1148 ;;
1149 esac
1150 case "$CONTENT_TYPE" in
1151 *boundary*)
1152 bndry=${CONTENT_TYPE#*boundary=}
1153 #for us in `LC_CTYPE=C ./mpsplit.rb "$bndry" $tmpd < $tmpf`
1154 for us in `LC_CTYPE=C ./mpsplit.pl "$bndry" $tmpd < $tmpf`
1155 do
1156 k=${us%%\=*}
1157 #echo u=$us
1158 #v="`echo ${us#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
1159 v="`echo ${us#*=}|unhexize|sed -e 's/\"/\"\"/g'`"
1160 # err k=$k v=$v
1161 case "$k" in
1162 *:filename)
1163 type='file'; k=${k%:filename}
1164 # DO NOT ALLOW Space and '|' in file names
1165 newv=`echo "$v"|sed 's/[ \|]/X/g'`
1166 if [ x"$v" != x"$newv" ]; then
1168 fi
1169 # (echo k=$k v="[$v]"; ls -lF "$tmpd/$v"; file --mime-type "$tmpd/$v") 1>&3
1170 case `file --mime-type - < "$tmpd/$v"|cut -d' ' -f2` in
1171 [Ii]mage/x-xcf)
1172 bzip2 "$tmpd/$v"
1173 v=${v}.bz2
1174 ;;
1175 [Ii]mage/x-*|*/vnd.*) ;;
1176 [Ii]mage/*)
1177 mogrify -resize $maximagexy'>' "$tmpd/$v"
1178 ;;
1179 esac
1180 ;;
1181 *)
1182 type='string'
1183 ;;
1184 esac
1185 #sq $db "replace into par values('$session', '$k', '$type', \"$v\")"
1186 setpar "$k" "$type" "$v"
1187 done
1188 ;;
1189 *)
1190 setviastring par "$s"
1191 ;;
1192 esac
1194 email4group() {
1195 # Get for-$1=group email address(es) for $2...=users
1196 qgrp=`sqlquote "$1"`; shift
1197 users=`for i; do sqlquote "$i"; done`
1198 users=`echo $users|tr ' ' ','`
1199 sql="select coalesce(s.val, g.user) from grp_mem g
1200 left join grp_mem_s s on g.gname=s.gname and g.user=s.user
1201 and s.key='email'
1202 where g.gname=$qgrp and g.user in ($users);"
1203 query "$sql"
1205 email4groupbyuid() {
1206 # Get for-$1=group email address(es) for $2...=user-ids
1207 qgrp=`sqlquote "$1"`; shift
1208 uids=`echo "$@"`
1209 uids=`echo $uids|tr ' ' ','`
1210 sql="WITH
1211 grpemails AS (
1212 SELECT gname, user, val email
1213 FROM grp_mem NATURAL JOIN grp_mem_s
1214 WHERE key='email' AND gname=$qgrp),
1215 useremails AS (
1216 SELECT user.rowid rid, user.name, val email
1217 FROM user
1218 LEFT JOIN user_s
1219 ON user.name=user_s.name AND user_s.key='email')
1220 SELECT DISTINCT coalesce(g.email, u.name)
1221 FROM useremails u LEFT JOIN grpemails g
1222 ON u.name=g.user
1223 WHERE u.rid in ($uids);"
1224 ## err email4gByid `echo $sql`
1225 query "$sql"
1227 collectemail() (
1228 # Collect email addresses for group $1
1229 # If $TEAM is set, filter by team name
1230 # If $EXCEPT is set as username(s) delimited by comma,
1231 # remove $EXCEPT from list: ....NOT IN ($EXCEPT)
1232 for e; do
1233 if isuser "$e"; then
1234 em=`query "select val from user_m where name='$e' and key='email';"`
1235 [ -n "$em" ] && echo "$em" || echo "$e"
1236 else
1237 qgrp=`sqlquote "$e"`
1238 if [ -z "$TEAM" ]; then
1239 gmem="grp_mem"
1240 else
1241 tm=`sqlquote "$TEAM"`
1242 gmem="(SELECT gname, user FROM grp_mem_m WHERE gname='$e' AND key='team' AND val=$tm)"
1243 fi
1244 ex=${EXCEPT:+"AND g.user NOT IN ($EXCEPT)"}
1245 sql="select coalesce(s.val,um.val,g.user) from
1246 $gmem g left join grp_mem_s s
1247 on g.gname=s.gname and g.user=s.user and s.key='email'
1248 left join user_m um on g.user=um.name and um.key='email'
1249 where g.gname=$qgrp $ex;"
1250 ## err CollectEmail: `echo "$sql"`
1251 query "$sql"
1252 fi
1253 done
1255 sendinvitation() (
1256 # $1=email
1257 iss="invite-`date +%s`-$user"
1258 addsession $iss +${memoplimitdays}days # 1 week due date
1259 query "replace into par values('$iss', 'invite', 'string', \"$1\");"
1260 gecos=`gecos`
1261 name=$user"${gecos:+($gecos)}"
1262 regist="$urlbase?reg+$iss"
1263 _m4 -D_URL_="$urlbase" \
1264 -D_USER_="$name" \
1265 -D_EMAIL_="$1" \
1266 -D_REGIST_="$regist" \
1267 -D_ADMIN_="$admin" \
1268 $msgdir/mail-invite.m4 \
1269 | smail $1 "BBSへの御招待"
1270 return 0
1272 emaildomaincheck() {
1273 case "$1" in
1274 *@*@*) echo "無効なアドレスです"; return 1 ;;
1275 *@*)
1276 local=${1%@*} domain=${1#*@}
1277 if ! host $domain >/dev/null 2>&1; then
1278 echo "ドメイン($domain)が見付かりません。"
1279 return 2
1280 fi
1281 return 0
1282 ;;
1283 *) echo "正しいメイルアドレスをいれてください"; return 3 ;;
1284 esac
1286 invite() {
1287 email=`getpar email`
1288 case $email in
1289 *@*@*) repo="無効なアドレスです" ;;
1290 *@*)
1291 local=${email%@*} domain=${email#*@}
1292 if ! repo=`emaildomaincheck $email`; then
1293 repo="招待アドレスのエラー: $repo"
1294 elif [ -n "`query \"select * from user where name='$email';\"`" ]; then
1295 repo="$email さんは既に加入しています。"
1296 elif sendinvitation $email; then
1297 repo="アドレス($email)宛に案内を送信しました。"
1298 fi ;;
1299 "") repo="招待したい人のメイルアドレスを入力してください。" ;;
1300 *) repo="無効なアドレスです" ;;
1301 esac
1302 addr=`query "select val from par where sessid like 'invite-%-$user';"`
1303 if [ -n "$addr" ]; then
1304 susp="<h2>招待済みで加入待ちのアドレス</h2><pre>$addr</pre>"
1305 fi
1306 _m4 -D_TITLE_="招待" -D_REPORT_="\`$repo'" -D_ACTION_="?invite" \
1307 -D_BODYCLASS_="default" -D_SUSPENDED_="$susp" \
1308 $layout/html.m4.html $layout/invite.m4.html
1310 regist() {
1311 # $1=session-id-for-invitation
1312 _m4 -D_TITLE_="Invitation" $layout/html.m4.html
1313 if [ -z "$1" ]; then
1314 echo "bye bye" | html p
1315 reutrn
1316 fi
1317 email=`session=$1 getpar invite`
1318 if [ -z "$email" ];then
1319 cat<<EOF
1320 <p>無効な招待状チケットです。</p>
1321 <p>招待状の有効期限(1週間)が切れているか、チケット番号が異なっています。
1322 加入している人に、再度招待してもらいましょう。</p>
1323 EOF
1324 return
1325 fi
1326 echo "$email さんようこそ" | html h2
1327 query "replace into user values('$email');"
1328 # Fake login password to wasureta
1329 query "replace into par values('$session', 'pswd', 'string', 'wasureta'),
1330 ('$session', 'user', 'string', '$email');"
1331 wasureta $email
1332 echo "このアドレスに初期パスワードを送信しました。" |html p
1333 echo "新着メイルを確認してログインしてください。" |html p
1334 addsession $1 # for removal after 1 minute
1335 _m4 -D_SYSNAME_="Initial Login" -D_MYNAME_="$myname?userconf" \
1336 $layout/login.m4.html
1337 return
1339 group_safename() {
1340 # Convert $1 to safe group name
1341 echo "$1" | tr -d '"'"'",
1343 groupupdate() {
1344 gname=`getpar gname`
1345 qgname=`sqlquote $gname`
1346 if [ -n "$gname" ]; then
1347 # See ALSO same job in showgroup()
1348 newgname=`group_safename "$gname"`
1349 err newgname=$newgname
1350 if [ x"$newgname" != x"$gname" ]; then
1351 err NewGNAME: gname=$newgname
1352 gname=$newgname
1353 echo "使用禁止文字を除去し $gname としました。" | html p
1354 replpar gname string "$gname"
1355 fi
1356 # Name confliction check
1357 parow=`getpar rowid`
1358 ## err parow=$parow
1359 qgname=`sqlquote $gname` # Set again in case gname modified
1360 query "BEGIN EXCLUSIVE;"
1361 ## err "select count(gname) from grp where rowid != ${parow:-0} and gname = $qgname;"
1362 count=$(query "select count(gname) from grp where rowid != ${parow:-0} and gname = $qgname;")
1363 if [ $count -gt 0 ]; then
1364 echo "そのグループ名は既にあります。" | html p
1365 query "END;"
1366 return
1367 fi
1368 par2table $formdir/grp.def
1369 query "END TRANSACTION;"
1370 # Remove orphan
1371 : <<EOF
1372 select a.id,b.val from (select * from blog where id in
1373 (select id from blog_s where key='owner'
1374 and val not in (select name from user union select gname from grp)))
1375 a left join blog_s b on a.id=b.id and b.key='owner';
1376 EOF
1377 rm=`getpar rm` cfm=`getpar confirm`
1378 ## err groupupdate:::: after par2tbl rmcfm=$rm$cfm
1379 if [ x"$rm$cfm" = x"yesyes" ]; then
1380 if [ -z "`query \"select gname from grp where gname=$qgname;\"`" ]; then
1381 sql="delete from blog where id in
1382 (select id from blog_s where key='owner' and val=$qgname);"
1383 err rm-grp cleaning sql=`echo $sql`
1384 query "$sql";
1385 grps # When removing a group, switch to grp-list
1386 return # and return
1387 fi
1388 fi
1389 [ -z "$parow" ] && joingrp "$gname" "$user" yes "" as-admin
1390 fi
1391 sql="select rowid from grp where gname=$qgname;"
1392 grid=$(query $sql)
1393 ## err grpupdate:new-grid=$grid, sql=$sql
1394 grp $grid
1396 groupclone() {
1397 # $1=grp-rowid of clone-base group
1398 qgrp=`query "SELECT quote(gname) FROM grp WHERE rowid=$1;"`
1399 if [ -z "$qgrp" ]; then
1400 echo "無効なグループIDです($1)" | html p
1401 return
1402 fi
1403 i=0
1404 while true; do
1405 copy="-copy$i"
1406 newqname=`query "SELECT quote($qgrp || '$copy');"`
1407 # err Trying new grp=$newqname with copy=$copy
1408 test=`query "SELECT gname FROM grp WHERE gname=$newqname;"`
1409 if [ -n "$test" ]; then
1410 i=$((i++))
1411 continue
1412 fi
1413 break
1414 done
1415 # Creating New group "$newqname" with members of old group
1416 # err Creating new grp=$newqname with copy=$copy
1417 query<<-EOF
1418 BEGIN;
1419 INSERT INTO grp VALUES($newqname); -- Create NEW one
1420 REPLACE INTO grp_s(gname, key, val) -- Copy tag
1421 SELECT $newqname, key, val
1422 FROM grp_s WHERE gname=$qgrp AND key IN ('tag', 'mode');
1423 REPLACE INTO grp_s(gname, key, type, val) -- Copy gecos with "copy$n"
1424 SELECT $newqname, key, type, val || '$copy'
1425 FROM grp_s WHERE gname=$qgrp AND key='gecos';
1426 -- Copy members and their configuration --
1427 REPLACE INTO grp_mem SELECT $newqname, user
1428 FROM grp_mem WHERE gname=$qgrp;
1429 REPLACE INTO grp_mem_s SELECT $newqname, user, key, type, val, bin
1430 FROM grp_mem_s WHERE gname=$qgrp;
1431 REPLACE INTO grp_mem_m SELECT $newqname, user, key, type, val, bin
1432 FROM grp_mem_m WHERE gname=$qgrp;
1433 -- Copy administrators --
1434 REPLACE INTO grp_adm SELECT $newqname, user
1435 FROM grp_adm WHERE gname=$qgrp;
1436 COMMIT;
1437 EOF
1438 newrowid=`query "SELECT rowid FROM grp WHERE gname=$newqname;"`
1439 STOPCLONEMSG=1 groupconf "$newrowid"
1441 groupman() {
1442 note="<p>グループ名に使用できない文字は自動的に削除されます。</p>"
1444 GF_STAGE="grpconf"
1445 GF_STAGE=groupupdate
1446 DT_VIEW=grp dumptable html grp 'gname gecos:DESC mtime:TIME' 'order by b.TIME desc' \
1447 |_m4 -D_TITLE_="グループ作成" \
1448 -D_FORM_="$note`genform $formdir/grp.def`" \
1449 -D_DUMPTABLE_="syscmd(cat)" \
1450 $layout/html.m4.html $layout/form+dump.m4.html
1452 userconf() {
1453 [ -n "`getpar rowid`" ] && par2table $formdir/user.def
1454 _m4 -D_BODYCLASS_=userconf -D_TITLE_="ユーザ情報編集" $layout/html.m4.html
1455 GF_ACTION="?home" edittable "$formdir/user.def" "user" "$user"
1457 groupconf() {
1458 # $1=rowid in grp (2015-07-21 changed from gname)
1459 [ -n "`getpar rowid`" ] && par2table $formdir/grp.def
1460 _m4 -D_BODYCLASS_=groupconf -D_TITLE_="グループ情報編集" $layout/html.m4.html
1461 #rowid=`query "select rowid from grp where gname='$1';"`
1462 rowid=${1%%[!A-Z0-9a-z_]*}
1463 # GF_ACTION="?grp+$1" edittable "$formdir/grp.def" "grp" "$rowid" #2015-0804
1464 GF_STAGE="groupupdate" edittable "$formdir/grp.def" "grp" "$rowid"
1465 if [ -z "$STOPCLONEMSG" ]; then
1466 echo "同じ構成員で新規グループ<a href=\"?groupclone+$rowid\">作成</a>" \
1467 | html p
1468 fi
1470 mems() {
1471 _m4 -D_TITLE_="参加者一覧" -D_BODYCLASS_=listmember $layout/html.m4.html
1472 kwd=`getpar kwd`
1473 listmember $kwd
1475 grps() {
1476 _m4 -D_TITLE_="グループ一覧" -D_BODYCLASS_=listgroup $layout/html.m4.html
1477 kwd=`getpar kwd`
1478 listgroup $kwd \
1479 | _m4 -D_DUMPTABLE_="syscmd(cat)" \
1480 -D_TITLE_="グループ関連操作" \
1481 -D_FORM_="<a href=\"?groupman\">新規グループ作成</a>" \
1482 $layout/form+dump.m4.html
1484 grp() { # $1=group-rowid
1485 gpg=`getpar grp`
1486 grid=${1:-$gpg}
1487 grp=`getgroupbyid "$grid"`
1488 ## . ./s4-blog.sh
1489 jg=`getpar joingrp`
1490 if [ -n "$jg" ]; then
1491 [ -n "$jg" -a -n "$grp" ] &&
1492 joingrp "$grp" "$user" "$jg" "`getpar email`"
1493 fi
1494 htmlheader=$layout/html.m4.html
1495 showgroup "$grid"
1497 sql4interestblogs() {
1498 cat<<EOF
1499 CREATE TEMPORARY VIEW interestblogs AS
1500 SELECT blog.rowid rid, id, author
1501 FROM blog
1502 NATURAL JOIN
1503 (SELECT id, val owner FROM blog_s WHERE key='owner') bs
1504 WHERE CASE WHEN (SELECT name FROM user where name=bs.owner) IS NOT NULL
1505 THEN 1 -- blog owner is an user, READABLE
1506 WHEN (SELECT user FROM grp_mem
1507 WHERE gname=bs.owner AND user='$user') IS NULL
1508 THEN 0
1509 ELSE 1
1510 END;
1511 EOF
1513 listnewblogsql() { # $1=user
1514 deftime=`query "SELECT coalesce((SELECT time FROM acclog
1515 WHERE user='$user'
1516 AND tblrowid=$blogreadflagrowid),
1517 "0");"`
1518 cat<<EOF
1519 `sql4interestblogs`
1520 WITH article_ctime as (
1521 SELECT id,blogid,author,val ctime
1522 FROM article join article_s s using(id)
1523 WHERE s.key='ctime'
1524 ), blog_title_owner as (
1525 SELECT blg.rid brid, id,
1526 max(case key when 'title' then val end) title,
1527 max(case key when 'owner' then val end) owner
1528 FROM interestblogs blg, blog_s using(id) group by id
1529 ), visited AS (
1530 SELECT b.id id, brid, b.owner owner, b.title title, ctime, ac.author author
1531 FROM blog_title_owner b, article_ctime ac
1532 JOIN acclog al
1533 ON b.id=ac.blogid
1534 AND al.tbl='blog'
1535 AND al.tblrowid=brid
1536 AND al.user='$user'
1537 AND al.time < ctime
1538 AND '$deftime' < ctime
1539 ), unvisited as (
1540 SELECT b.id id, brid, b.owner owner, b.title title, ctime, ac.author author
1541 FROM blog_title_owner b, article_ctime ac
1542 ON b.id=ac.blogid
1543 WHERE brid NOT IN (SELECT tblrowid FROM acclog
1544 WHERE tbl='blog' AND user='$user')
1545 AND ctime > '$deftime'
1546 ), blogall as (
1547 /* ---------------------------------------
1548 Collect new articles with dividing them into visited and unvisited
1549 separately, because constructing joined table of artice X acclog
1550 tends to become HUGE combinations.
1551 --------------------------------------- */
1552 SELECT * FROM visited UNION SELECT * FROM unvisited
1553 ), news as (
1554 select bl.brid brid, bl.title, bl.id blid, ctime,
1555 count(bl.id) "新着", bl.owner, bl.author
1556 from blogall bl /* left join a_u l
1557 on bl.brid=l.tblrowid */
1558 group by bl.id order by ctime desc,"新着" desc, bl.id
1559 LIMIT 10
1560 ) SELECT brid LINK, "新着",
1561 (SELECT count(*) FROM article WHERE blogid=blid) "総数",
1562 ctime, title,
1563 (SELECT gecos FROM gecoses WHERE name=author) gecos
1564 FROM news;
1565 EOF
1568 search_form() {
1569 help="(1)空白区切りの単語で本文検索
1570 (2)@YYYY-MM-DD 日付け(シェルパターン可)で日付け検索
1571 @2016-0[1-6] → 2016年1月から6月
1572 @>2016-01 @<2016-02-15 → 2016年1月から2月14日までの期間
1573 @week → 最近一週間
1574 (3)#番号 で記事ID検索
1575 (1)と(2)は組み合わせOK
1576 例: @2016-10-0[1-9] 芋煮
1577 → 2016年10月上旬でキーワード「芋煮」を含む記事検索"
1578 auth=""
1579 placeholder="全記事からの検索"
1580 case "$1" in
1581 author=*)
1582 a=`echo "${1#author=}"|htmlescape`
1583 g=`gecos ${1#author=}`
1584 auth="<input type=\"hidden\" name=\"author\" value=\"$a\">"
1585 placeholder="このユーザの書込検索"
1586 help="★★ $g さんの書き込みから検索します$nl$help"
1587 ;;
1588 esac
1589 cat<<-EOF
1590 <div class="fr">
1591 <form action="$myname">$auth
1592 <input type="text" name="kwd" value="" title="$help"
1593 placeholder=" $placeholder " width="10" accesskey="k">
1594 ${touchpanel:+<p class="help">$help</p>}
1595 <input type="hidden" name="stage" value="searchart">
1596 </form>
1597 </div>
1598 EOF
1601 imgsrc_cache() (
1602 # $1 = directory for cache'ing
1603 # $2 = table (user_m or grp_m)
1604 # $3 = keycond (was: condition for choosingowner)
1605 # $4 = size : S = Small, M = Medium, O = Original
1606 dir="$1" tbl="$2"
1607 keycond="$3"
1608 whos="$keycond AND key='profimg' AND type LIKE 'file:image%'
1609 ORDER BY rowid DESC LIMIT 1"
1610 [ -d "$dir" ] || mkdir -p "$dir"
1611 tmpf=$tmpd/imgsrc_cache.$$
1612 case "$4" in
1613 [Ss]) size=S ;;
1614 [Oo]) size=O ;;
1615 *) size=M ;;
1616 esac
1617 # ImageCache filename storing schema:
1618 # <table_s>.{key, val}={"profimgcache_S", "$cacheimg_S"}
1619 sql0="SELECT val || '//' || type FROM $tbl WHERE $whos;"
1620 sql1="SELECT hex(bin) FROM $tbl WHERE $whos;"
1621 valtype=`query "$sql0"`
1622 filename=${valtype%%//*}
1623 filetype=${valtype##*//file:}
1624 if [ x"$filename" = x"${filename%.*}" ]; then
1625 # If nor filename extension found, set it to image type
1626 case "$filetype" in
1627 image/*) filename=$filename.${filetype#image/} ;;
1628 esac
1629 fi
1630 cacheimg_S=$dir/S_$filename
1631 cacheimg_M=$dir/M_$filename
1632 cacheimg_O=$dir/$filename
1633 cacheimg=$dir/${size}_$filename
1634 sumfile="$dir/$filename.sum"
1635 sum=`query "$sql1" | tee $tmpf | encode` # encode() is maybe sha1
1636 if test -s "$sumfile" && [ x"`cat \"$sumfile\"`" = x"$sum" ] \
1637 && test -s "$cacheimg_S" && test -s "$cacheimg_M" ; then
1638 # if cache is fresh and has the same checksum,
1639 echo "<img src=\"$cacheimg\">"
1640 else
1641 fifo=`mktemp "$tmpf.fifo.XXXXXXX"`
1642 rm -f $fifo # Safe, because $tmpf is in mktemp dir.
1643 fifo2=$fifo.2
1644 mkfifo $fifo $fifo2
1645 fmt=${filename##*.}
1646 ## [[ NOTE ]]
1647 ## a. convert oldimage newimage
1648 ## b. convert oldimage fmt:- | convert - newimage
1649 ## b is much smaller than a
1650 cat $tmpf | unhexize \
1651 | tee $fifo \
1652 | convert -define ${fmt}:size=${iconxy_M} \
1653 -resize ${iconxy_M}'>' - ${fmt}:- \
1654 | tee $fifo2 \
1655 | convert - "$cacheimg_M" &
1656 cat $fifo | convert -define ${fmt}:size=${iconxy_S} \
1657 -resize ${iconxy_S}'>' - ${fmt}:- \
1658 | convert - "$cacheimg_S" &
1659 printf '%s' "<img src=\"data:${filetype},"
1660 hexize "$fifo2" |sed 's/\(..\)/%\1/g' # Use medium as pre-cached image
1661 echo '">'
1662 echo "$sum" > $sumfile
1663 fi
1664 ## Now preparing cache image, done.
1665 ## Store this information to DB
1666 stbl=${tbl%_m}_s # user_s or grp_s
1667 pkey=${keycond%%=*} # Primary Key name
1668 pval=${keycond#*=} # Primary Key value
1669 query <<-EOF
1670 REPLACE INTO $stbl($pkey, key, type, val)
1671 VALUES($pval, '$iconcachekey', 'string', `sqlquote "$cacheimg_S"`);
1672 EOF
1675 showhome() {
1676 # $1=userRowIdToShow
1677 err showhome \$1=$1
1678 case "$1" in
1679 *@*) uname=`getvalbypkey user name "$1"` ;;
1680 *) uname=`getvalbyid user name $1` ;;
1681 esac
1682 ## err ShowHome: uname=$uname
1683 td=`getcachedir home/"$1"`
1684 gecos=`gecos "$uname"`
1685 ## err SH:gecos=$gecos
1686 GF_VIEWONLY=1
1687 cond="gname in (select gname from grp_mem where user='$uname')"
1688 search_form_args=""
1689 if [ x"$user" = x"$uname" ]; then
1690 conflink="<a href=\"?userconf\" accesskey=\"e\"
1691 title=\"E\">プロフィールの編集</a> /
1692 <a href=\"?blog\" accesskey=\"n\" title=\"N\">新規話題の作成</a>"
1693 # Display folders
1694 sql="select count(id) from article_m where id
1695 in (select id from article where author='$user')
1696 and type like 'file:%';"
1697 ## err nfile-sql=`echo "$sql"`
1698 nfile=`query "$sql"`
1699 # err nfile=$nfile
1700 if [ $nfile -gt 0 ]; then
1701 conflink="$conflink / <a href=\"?lsmyfile\" accesskey=\"l\"
1702 title=\"L\">過去の提出ファイル</a>"
1703 fi
1704 else
1705 search_form_args="author=$uname"
1706 fi
1707 . ./s4-blog.sh
1709 tf=$tmpd/title.$$ pf=$tmpd/profile.$$ bf=$tmpd/blogs.$$ sf=$tmpd/search.$$
1710 search_form $search_form_args > $sf
1711 echo "$gecos さん" > $tf
1712 { echo "<div class=\"noprofimg\">"
1713 viewtable $formdir/user.def user $1
1714 echo "</div>"
1715 } > $pf
1717 sqcond="WHERE name='$uname' AND key='profimg' AND type LIKE 'file:image%'"
1718 img=`query "SELECT type FROM user_m $sqcond LIMIT 1;"`
1719 imf=$tmpd/profimg.$$; touch $imf
1720 if [ -n "$img" ]; then
1721 if true; then
1722 tbl=user_m
1723 enticond="name='$uname'"
1724 imgsrc_cache "$td/main" user_m "$enticond" M
1725 else
1726 { printf '%s' "<IMG src=\"data:${img#file:},"
1727 query "SELECT hex(bin) FROM user_m $sqcond ORDER BY rowid LIMIT 1;" \
1728 | sed 's/\(..\)/%\1/g'
1729 echo '">'
1731 fi > $imf
1732 fi
1733 nblog=`query "SELECT count(id) FROM blog_s WHERE key='owner' AND \
1734 val='$uname';"`
1735 listblog $uname > $bf
1737 hometail=$tmpd/tail.$$
1738 mkfifo $hometail
1740 #Calling listgroupbytable, originally here
1743 # Display Most Recent Entry
1744 shortval=${dumpcollen:+"substr(val, 0, $dumpcollen)"}
1745 shortval=${shortval:-val}
1747 # The m.aid in the next line is suspicious. But works fine in SQLite3...
1748 DT_SQL="SELECT b.rowid || '#' || m.aid LINK,
1749 ctime,
1750 (SELECT $shortval FROM blog_s WHERE key='title' AND id=b.id) title,
1751 (SELECT gecos FROM gecoses
1752 WHERE name=(SELECT val FROM blog_s
1753 WHERE key='owner' AND id=b.id)) owner,
1754 (SELECT $shortval val FROM article_s WHERE id=m.aid AND key='text') text
1755 FROM blog b
1756 JOIN
1757 (SELECT distinct blogid, a.id aid, max(val) ctime
1758 FROM article a, article_s s
1759 ON a.id=s.id AND a.author='$uname' AND s.key='ctime'
1760 GROUP BY blogid ORDER BY val DESC LIMIT 50
1761 ) m
1762 ON b.id=m.blogid;"
1763 # This should be as follows
1764 : <<EOF
1765 WITH arts AS(
1766 SELECT (SELECT rowid FROM blog WHERE id=a.blogid) brid,
1767 a.blogid, a.id id, s.val ctime
1768 FROM article a NATURAL JOIN article_s s
1769 WHERE s.key = 'ctime' AND a.author='$user'
1770 GROUP by s.id
1772 SELECT a0.brid,a0.blogid,a0.id,a0.ctime
1773 FROM arts a0
1774 JOIN
1775 (SELECT blogid,max(ctime) mct FROM arts a1 GROUP BY blogid) a1
1776 ON a0.blogid=a1.blogid AND a0.ctime=a1.mct
1777 ORDER BY ctime DESC LIMIT 50;
1778 EOF
1780 cat<<-EOF
1781 `cgi_radio foldtabs yes 'id="mre" accesskey="d"'`<label
1782 for="mre" title="D">最近の書き込み先</label>
1783 <div class="lcto">
1784 `DT_VIEW=replyblog dumptable html blog`
1785 </div>
1786 EOF
1787 unset DT_SQL
1788 if [ x"$user" = x"$uname" ]; then
1789 # Display NEWS
1790 # 2016-06-26
1791 if [ x"`getpar readchk``getpar read`" = x"yesyes" ]; then
1792 acclog blog $blogreadflagrowid
1793 # echo "全部既読にしました" | html p
1794 fi
1795 # 2016-02-19 Counting NEWS without using dumptable.
1796 sql=`listnewblogsql "$user"`
1797 new10=`DT_SQL="$sql" DT_VIEW=replyblog dumptable html blog`
1798 cont=`echo "$new10"|grep "^<TR>"|wc -l`
1799 cont=$((cont-1))
1800 err newcount=$cont
1801 if [ $cont -gt 0 ]; then
1802 #echo "全体の新着記事${cont}傑" | html h2
1803 cgi_radio foldtabs yes 'id="new10" accesskey="f"'
1804 echo "<label for=\"new10\" title=\"X\">新着${cont}傑</label><div>"
1805 cat<<-EOF | html form 'action="?home"'
1806 `cgi_checkbox readchk yes 'id="read"'`<label
1807 for="read">新着ふくめて全部読んだことにする</label>
1808 `cgi_submit '確定'`
1809 `cgi_hidden read yes`
1810 EOF
1811 echo "$new10 <!-- new10 -->"
1812 echo "</div>"
1813 fi
1814 else # Not My Home ($user != $uname)
1815 : # DT_SQL=
1816 fi
1817 ) > $hometail & # Is background call safe to m4??
1819 listgroupbytable $formdir/grp.def $cond |
1820 _m4 -D_BODYCLASS_=home -D_TITLE_="spaste(\`$tf')" \
1821 -D_PROFILE_="spaste(\`$pf')$conflink" \
1822 -D_PROFIMG_="spaste(\`$imf')" \
1823 -D_BLOGS_="spaste(\`$bf')" \
1824 -D_SEARCH_="spaste(\`$sf')" \
1825 -D_NBLOG_="$nblog" \
1826 -D_GROUPS_="syscmd(\`cat')" \
1827 -D_HOMETAIL_="syscmd(\`cat $hometail')" \
1828 $layout/html.m4.html $layout/home.m4.html
1830 # Record access log
1831 [ -n "$1" ] && [ x"$1" != x"$user" ] && acclog user $1
1833 commission() { # $1=grp-rowid $2=user-rowid
1834 contenttype; echo
1835 ## err commission: "$@"
1836 gname=`getgroupbyid $1`
1837 echo "グループ $gname 管理者委任" \
1838 | _m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1839 if [ -n "$2" ]; then
1840 grp_reg_adm "$@"
1841 else
1842 echo "無効な指定です。普通のアクセスならここに来ないはず。"|html p
1843 fi
1845 listgroupbytable() {
1846 # $1=deffile $2...=condition
1847 tagline=`grep :tag: $1`; shift
1848 and="${1:+and }" where=${1:+where }
1849 href="<a href=\"$myname?grp+"
1850 echo '<div class="listgroup">'
1851 NGsql="select distinct tag from\
1852 (select gname, max(case key when 'tag' then val end) as tag, \
1853 max(case key when 'ctime' then val end) as ctime\
1854 from grp_s group by gname order by ctime);"
1855 sql="select val from grp_s where key='tag' $and$* group by val;"
1856 ## err ListGRP: query sql="$sql"
1857 for tag in `query "$sql"`
1858 do
1859 ## err ListGrp: tag=$tag
1860 tn=${tagline%%=${tag}*}
1861 tn=${tn##*[ :]}
1862 sql="select rowid||':'||gname as 'グループ名',説明 from
1863 (select (select rowid from grp g where g.gname=grp_s.gname)
1864 as rowid,
1865 gname,
1866 max(case key when 'gecos' then val end) as '説明',
1867 max(case key when 'tag' then val end) as 'tag',
1868 max(case key when 'mtime' then val end) as mtime from grp_s
1869 $where$* group by gname having tag='$tag' order by mtime desc);"
1870 ## err PersonalGroupList= `echo $sql`
1871 echo "<h2>$tn</h2>"
1872 echo '<table class="b listgroup">'
1873 sq -header -html $db "$sql" \
1874 | sed "s,\(<TR><TD>\)\([0-9]*\):\([^ ]*\)</TD>,\1$href\2\">\3</a>,"
1875 echo '</table>'
1876 done
1877 echo '</div>'
1879 iconhref() (
1880 # $1=icon-file, $2=Href $3=title $4...=anchor
1881 data=`percenthex "$1"`
1882 ct=`file --mime-type - < "$1"|cut -d' ' -f2`
1883 ## err iconhref: \$1=$1 \$2=$2 \$3="$@"
1884 href=$2; title=$3; shift 3
1885 echo "<a href=\"$href\"><img title=\"$title\" src=\"data:$ct,$data\">$@</a>"
1887 iconhref2() (
1888 # $1=icon-file, $2=Href $3=title $4...=anchor
1889 src=$1
1890 href=$2; title=$3; shift 3
1891 echo "<a href=\"$href\"><img title=\"$title\" src=\"$src\">$@</a>"
1893 listentry() (
1894 # $1=user/group $2=SearchKeyword $3=condition(if any) $4=grprowid(if in grp)
1895 # Referring variable $iamowner=$grp to attach owner-request links
1896 ## err listentry: \$1=$1 \$2=$2 \$3=$3
1897 cond='' hiddens=''
1898 offset=`getpar offset`
1899 offset=${offset%%[!0-9]*}
1900 offset=$((offset + 0)) # change to numeric forcibly
1901 [ $offset -lt 0 ] && offset=0
1902 limit=30
1903 dir=`getcachedir "$1"`
1904 if [ x"$1" = x"user" ]; then
1905 hrb="$myname?home"
1906 deficon=person-default.png
1907 entity="ユーザ" tbl=user link=rowid nm=name # stage=mems
1908 [ -n "$4" ] && hiddens=`cgi_hidden grid $4`
1909 gcs=gecos
1910 else # if group
1911 hrb="$myname?grp"
1912 deficon=group-default.png
1913 entity="グループ" tbl=grp link=rowid nm=gname stage=grps
1914 gcs=name
1915 tagline=`grep :tag: $formdir/grp.def|cut -d: -f5-`
1916 if [ -n "$tagline" ]; then
1917 tagconv=`echo $tagline|sed 's/\([^= :]*\)=\([^= :]*\)/-D\2=\1/g'`
1918 ## err tagconv=$tagconv
1919 fi
1920 fi
1921 if [ ! -d $dir ]; then
1922 mkdir -p $dir
1923 fi
1924 if [ ! -s $dir/$deficon ]; then
1925 convert -geometry $thumbxy $imgdir/$deficon $dir/$deficon
1926 fi
1927 if [ -n "$2" ]; then
1928 cond="where nick like '%$2%' or b.name like '%$2%'"
1929 fi
1931 # XX: これ複雑すぎるかな。もっとシンプルにしたい。$3条件も。2015-07-08
1932 # grpは呼出し元の動的スコープ変数でよくないな...
1933 ##qgrp=`sqlquote $grp`
1934 getgrp="(select gname from grp where rowid=${rowid:--1})"
1935 sql="select a.rowid, a.$link,
1936 coalesce(b.$gcs, a.$nm) as nick,
1937 quote(a.$nm) as qname,
1938 (SELECT val FROM ${tbl}_s
1939 WHERE $nm=a.$nm AND key='$iconcachekey') icon,
1940 coalesce(b.gecos, a.$nm) /* If group, concat (Nusers) */
1941 || case when a.$nm in (select gname from grp)
1942 then printf('(%d名)',
1943 (select count(user) from grp_mem where gname=a.$nm))
1944 else ' <'||a.$nm||'>'
1945 end
1946 as name,
1947 b.tag,
1948 case when a.$nm in (select user from grp_adm
1949 where gname=$getgrp) then '(管理者)'
1950 when '$user' in (select user from grp_adm where gname=a.$nm)
1951 then '(ADMIN)'
1952 when '$user' in (select user from grp_mem where gname=a.$nm)
1953 then '(Member)'
1954 when '$iamowner' = '' then ''
1955 else ',not='||a.rowid end as ownerlink,
1956 CASE '$entity'
1957 WHEN 'グループ'
1958 THEN coalesce(
1959 (SELECT val FROM grp_s WHERE gname=a.$nm AND key='regmode'),
1960 'open')
1961 ||
1962 CASE WHEN '$user'
1963 IN (SELECT user FROM grp_mem WHERE gname=a.$nm)
1964 THEN ' ismember'
1965 ELSE ''
1966 END
1967 ELSE 'user'
1968 END regmode
1969 from $tbl a left join
1970 (select $nm as name,
1971 max(case key when 'gecos' then val end) as gecos,
1972 max(case key when 'tag' then val end) as tag,
1973 max(case key when 'mtime' then val end) as mtime,
1974 max(case key when 'wtime' then val end) as wtime
1975 from ${tbl}_s group by $nm)
1976 b on a.$nm=b.name $cond $3
1977 order by b.tag desc, b.wtime desc, b.mtime desc, a.rowid asc"
1978 # Give precedence to newer maintained groups (2016-09-24)
1979 # Note that mtime is stored only in grp_s.
1980 ## err LE:sql.1="$sql"
1981 total=`query "with x as ($sql) select count(*) from x;"`
1982 echo "${entity} 一覧" | html h2
1983 if [ $total -gt $limit ]; then
1984 echo '<div class="right">'
1985 cgi_form $stage <<EOF
1986 <label>次の語を含む${entity}で検索:
1987 `cgi_text kwd $kwd`</label>
1988 EOF
1989 echo '</div>'
1990 fi
1991 hiddens="$hiddens
1992 `cgi_hidden kwd \"$kwd\"`
1993 `cgi_hidden stage \"$stage\"`"
1994 cat<<EOF
1995 <p>${total}件中の$((offset+1))件めから${kwd:+" - 検索語: $kwd"}</p>
1996 EOF
1997 if [ $((offset+limit)) -lt $total ]; then
1998 nextbtn=$(
1999 cat<<EOF
2000 <div class="right clear"><form action="$myname" method="POST">
2001 `cgi_submit 次の${limit}件`
2002 $hiddens
2003 `cgi_hidden offset $((offset + limit))`</form></div>
2004 EOF
2006 fi
2007 if [ $offset -gt 0 ]; then
2008 prevbtn=$(
2009 cat<<EOF
2010 <form action="$myname" method="POST">
2011 `cgi_submit 前の${limit}件`
2012 $hiddens
2013 `cgi_hidden offset $((offset - limit))`</form>
2014 EOF
2016 fi
2017 pnbtn="$nextbtn$prevbtn"
2018 echo $pnbtn
2020 ## err ListEntry: `echo "$sql"\;`
2021 # sq $db here??? 2016-11-28
2022 query "$sql limit $limit ${offset:+offset $offset};" \
2023 | while IFS='|' read id lnk name qname icon gecos tag ownerp type; do
2024 err name=$name owner=$ownerp lnk=$lnk
2025 err newlnk=$lnk regmode=$regmode
2026 icondir=$dir/$id
2027 # Pick up only last icon
2028 echo "<div class=\"iconlist xy$thumbxy $type\">
2029 <p class=\"tag _$tag\">$tag</p>" \
2030 | _m4 $tagconv
2031 if [ -n "$NOSPEEDUP" ]; then
2032 files=`getvalbyid $tbl profimg $id $icondir`
2033 if [ -n "$files" ]; then
2034 icon=`echo "$files"|tail -1`
2035 iconhref2 "$icondir/$icon" "$hrb+$lnk" "$gecos"
2036 else
2037 iconhref "$dir/$deficon" "$hrb+$lnk" "$gecos"
2038 fi
2039 elif [ -n "$icon" -a -s "$icon" ]; then
2040 iconhref2 "$icon" "$hrb+$lnk" "$gecos"
2041 else
2042 cond="$nm=$qname"
2043 # err imgsrc_cache "$dir/list" ${tbl}_m "$cond" S
2044 # err query "SELECT type FROM ${tbl}_m $cond LIMIT 1;"
2045 img=`query "SELECT type FROM ${tbl}_m WHERE $cond AND key='profimg' LIMIT 1;"`
2046 # err "img=[$img]"
2047 if [ -n "$img" ]; then
2048 echo "<a href=\"$hrb+$lnk\">"
2049 imgsrc_cache "$icondir" ${tbl}_m "$nm=$qname" S
2050 echo "</a>"
2051 else
2052 iconhref2 "$dir/$deficon" "$hrb+$lnk" "$gecos"
2053 fi
2054 fi
2055 echo "<br>$name${ownerp:+<br>$ownerp}"
2056 echo "</div>"
2057 done
2058 echo ${pnbtn:+"<hr>$nextbtn$prevbtn"}
2060 listmember() {
2061 listentry user "$@"
2063 listgroup() {
2064 listentry group "$@"
2066 hexteams() { # $1=gname, $2(optional)=user
2067 cond=${2:+" AND user='$2'"}
2068 query "SELECT DISTINCT hex(val) FROM grp_mem_m
2069 WHERE gname='$1' AND key='team'$cond;"
2071 showgroup() { # $1=group-rowid
2072 if [ -z "$1" ]; then
2073 grid=`getpar grid`
2074 grid=${grid%%[!0-9]*}
2075 [ -n "$grid" ] && grp=`getgroupbyid $grid`
2076 else
2077 grid=$1
2078 fi
2079 grp=`getgroupbyid $grid`
2080 qgrp=`sqlquote $grp`
2081 ## err showgroup2: grp=$grp qgrp="[$(sqlquote $grp)]"
2082 if isgroup "$grp"; then
2083 tf=$tmpd/title.$$
2084 bodyclass=`query "SELECT val FROM grp_s
2085 WHERE gname=$qgrp AND key='regmode';"`
2086 if ismember "$user" "$grp"; then
2087 ismember="ismember"
2088 qgrp=`sqlquote $grp`
2089 bodyclass="$bodyclass${bodyclass:+ }ismember"
2090 else
2091 ismember="" # bodyclass="group"
2092 fi
2093 bodyclass="$bodyclass grouphome"
2094 echo "グループ $grp" > $tf
2095 showgroupsub $formdir/grp.def "$grid" | \
2096 _m4 -D_TITLE_="spaste(\`$tf')" \
2097 -D_FORM_="syscmd(\`cat')" \
2098 -D_BODYCLASS_="$bodyclass" \
2099 -D_DUMPTABLE_="" \
2100 $htmlheader $layout/form+dump.m4.html
2101 # $htmlheader is defined in grp()
2102 else # if $grp is removed at par2table
2103 listgroup
2104 fi
2106 showgroupsub() {
2107 # $1=def-file $2=group-rowid
2108 # Using $ismember
2109 rowid=$2
2110 grp=`getgroupbyid $2`
2111 qgrp=`sqlquote $grp`
2112 td=`getcachedir grp/"$2"`
2113 #rowid=`sq $db "select rowid from grp where gname=$qgrp"`
2114 if [ -z "$rowid" ]; then
2115 #rowid=`sq $db "select rowid from grp where rowid=$grp"`
2116 #grp=`sq $db "select gname from grp where rowid=$grp"`
2117 echo "showgroupsub: invalid argument($1 $2)" | html p
2118 return
2119 fi
2120 val=`getvalbyid grp profimg $rowid $tmpd`
2121 enticond="gname=$qgrp"
2122 img=`query "SELECT type FROM grp_m WHERE $enticond LIMIT 1;"`
2123 if [ -n "$img" ]; then
2124 cat<<-EOF
2125 <p class="groupimg">
2126 `imgsrc_cache $td/main grp_m "$enticond" M`</p>
2127 EOF
2128 fi
2129 echo "<div class=\"noprofimg\">"
2130 viewtable $1 grp $rowid
2131 echo "</div>"
2132 if isgrpowner "$user" "$grp"; then
2133 echo "<p><a href=\"?groupconf+$rowid\">グループ情報の編集</a>"
2134 iamowner=$rowid
2135 colmd=" mode"
2136 fi
2137 if [ -n "$ismember" ]; then
2138 echo "${iamowner:+ / }<a href=\"?blog+$rowid\">グループの新規話題作成</a>"
2139 echo "/ <a href=\"?grpaction+$rowid\">メンバーを個別選択しての操作</a></p>"
2140 # div.fold input[type="checkbox"]:checked ~ div {display: block;}
2141 cat<<EOF
2142 <form action="?send2mem" method="POST" enctype="multipart/form-data">
2143 <div class="fold clear">
2144 `cgi_checkbox send yes id="send"`<label
2145 for="send">グループ全員にメッセージ送信</label>
2146 <div>
2147 `cgi_textarea message "" "cols=60"`
2148 `cgi_submit 送信`
2149 `cgi_reset リセット`
2150 </div>
2151 `cgi_hidden grp $rowid`
2152 </div></form>
2153 EOF
2154 fi
2155 # 加入ボタン + 加入者リスト
2156 if [ -n "$ismember" ]; then
2157 ismem='checked' state="(参加中)"
2158 else
2159 nomem='checked' state="(現在非加入)"
2160 fi
2161 # このグループでの加入アドレス
2162 eml=`query "select val from grp_mem_s where gname=$qgrp and user='$user' \
2163 and key='email';"`
2164 ##err EML: "select val from grp_mem_s where gname='$2' and user='$user' \
2165 ## and key='email';"
2166 ##err email=$eml
2167 cat <<EOF
2168 <div class="fold clear">
2169 `cgi_checkbox reg yes id="reg"`<label
2170 for="reg">自身の加入状態を操作する</label>$state
2171 <div>
2172 EOF
2173 cgi_form grp <<EOF
2174 <p>このグループに</p>
2175 <table class="b">
2176 <tr><th>メンバーとして</th><td>
2177 <label>`cgi_radio joingrp "yes" $ismem`参加</label> /
2178 <label>`cgi_radio joingrp "no" $nomem`参加しない</label></td></tr>
2179 <tr><th>参加する場合のメイルアドレス<br>
2180 <small>(メインのアドレスとは違うものにする場合に記入<br>
2181 同じでよい場合は空欄に)</small></th>
2182 <td>`cgi_text email $eml`</td></tr>
2183 </table>
2184 `cgi_hidden grp $rowid`
2185 EOF
2186 if [ x`getgroupattr $grp regmode` = x'moderated' -a -z "$ismem" ]; then
2187 echo "moderated (承認加入の)グループなので実際に参加できるのは
2188 グループ管理者が承認操作をした後になります。" | html p 'class="warn"'
2189 fi
2190 echo '</div></div>'
2191 echo '<h2>話題一覧</h2>'
2192 cgi_form searchart<<EOF
2193 <label>`cgi_text kwd`という語を含むコメントを検索</label>
2194 `cgi_hidden owner $grp`
2195 EOF
2196 cond="where a.id in (select id from blog_s where key='owner' and val=$qgrp) order by ctime desc"
2197 DT_CHLD=article:blogid \
2198 DT_VIEW=replyblog dumptable html blog \
2199 "ctime team title heading$colmd" "$cond"
2201 getgname="(select gname from grp where rowid=$rowid)"
2202 c="group by a.name having a.name in (select user from grp_mem where gname=$getgname)"
2203 cm="?commission+$rowid"
2204 thumbxy=50x50 listmember "" "$c" "$rowid" \
2205 |sed -e "s|\(<br>\),not=\(.*\)|\1|" # 間違って押しやすい
2206 # team list
2207 hexteams=`hexteams "$grp"`
2208 if [ -n "$hexteams" ]; then
2209 echo "チーム一覧" | html h2
2210 echo '<div class="dumptable"><table class="b">'
2211 sq $db -html -header<<-EOF
2212 SELECT val TEAM,
2213 group_concat((SELECT gecos FROM gecoses WHERE name=user), ',')
2214 MEMBERS
2215 FROM grp_mem_m WHERE gname=$qgrp AND key='team' GROUP BY val;
2216 EOF
2217 echo '</table></div>'
2218 fi
2220 grp_getbodyclass() {
2221 # Get css class name for document.
2222 # `moderated' for moderated groups
2223 # `ismember' for groups where user belongs
2224 # $1=GroupName (w/o quote)
2225 # $user=userNameCurrentlyLogin
2226 ## err grp_getbodyclass: 1="$1"
2227 qgrp=`sqlquote "$1"`
2228 query<<-EOF
2229 SELECT coalesce(
2230 (SELECT val FROM grp_s WHERE gname=$qgrp AND key='regmode'),
2231 'open')
2232 ||
2233 CASE WHEN '$user'
2234 IN (SELECT user FROM grp_mem WHERE gname=$qgrp)
2235 THEN ' ismember'
2236 ELSE ''
2237 END;
2238 EOF
2240 grpaction() { # $1=group-rowid
2241 err GRP_ACTION:IN
2242 grid=${1:-`getpar grp`}
2243 grp=`getgroupbyid "$grid"`
2244 if [ -z "$grp" ]; then
2245 echo "無効な指定です。" | html p; return
2246 fi
2247 if ! ismember $user $grp; then
2248 echo "加入者のみに許可された操作です。" | html p; return
2249 fi
2250 echo "グループ $grp 個別選択操作" \
2251 | _m4 -D_TITLE_="syscmd(\`cat')" \
2252 -D_BODYCLASS_="`grp_getbodyclass \"$grp\"`" \
2253 $layout/html.m4.html
2255 isowner=""
2256 isgrpowner "$user" "$grp" && isowner="yes"
2257 usel=`getpar usel`
2258 if [ -n "$usel" ]; then
2259 uids=$(echo `echo $usel`|tr ' ' ',')
2260 ## err grpaction-1: grp=$grp, `echo $sql`
2261 text=`getpar text`
2263 rm=`getpar rm` cfm=`getpar confirm`
2264 ## err rm=$rm cfm=$cfm
2265 if [ x"$rm" = x"yes" ]; then
2266 if [ "$isowner" ]; then
2267 if [ x"$rm$cfm" = x"yesyes" ]; then
2268 # Eliminate
2269 cond="where gname=(select gname from grp where rowid=$grid) and user in (select name from user where rowid in ($uids))"
2270 for tbl in grp_mem grp_mem_s grp_mem_m; do
2271 sql="delete from $tbl $cond;"
2272 # echo "sql=$sql"
2273 query "$sql"
2274 err rmGRPuser "$sql"
2275 done
2276 num=`query "select count(*) from user where rowid in ($uids);"`
2277 #err num=$num
2278 if [ 0$num -gt 0 ]; then
2279 sql="select coalesce(b.val,a.name) from user a left join \
2280 user_s b on a.name=b.name and key='gecos' where a.rowid in ($uids);"
2281 # err `echo "$sql"`
2282 html pre<<EOF
2283 以下の${num}名のグループ $grp 登録を解除しました。
2284 `query "$sql"`
2285 EOF
2286 fi
2287 else
2288 echo "確認のチェックがないのでやめておきます。" | html p
2289 return
2290 fi
2291 else # not Group Owner
2292 echo "グループ管理者でないのでメンバー操作はできません。" | html p
2293 return
2294 fi
2295 cat<<EOF
2297 EOF
2298 elif [ x"$rm" = x"send" ]; then # if sendmsg mode
2299 if [ -z "$text" ]; then # if msg is empty
2300 echo "なにかメッセージを..." | html p
2301 return 0
2302 fi
2303 gecos=`gecos $user`
2304 mkfrom=`getpar mkfrom`
2305 if [ x"$mkfrom" = x"yes" ]; then
2306 safegc=`echo "$gecos" | tr -d '<>@'`
2307 myuid=`query "SELECT rowid FROM user WHERE name='$user';"`
2308 fromad=`email4groupbyuid "$grp" "$myuid"`
2309 mail_from="$safegc <$fromad>"
2310 else
2311 mail_from="$admin"
2312 fi
2313 MAIL_FROM=$mail_from \
2314 smail "`email4groupbyuid "$grp" $usel` $user" \
2315 "$gecos さんからのメッセージ" <<EOF
2316 $url
2317 のグループ「$grp」のメンバーである $gecos さんから、
2318 あなた宛へのメッセージです。
2319 ----------------------------------------------------------
2320 $text
2321 EOF
2322 if [ $? = 0 ]; then
2323 echo "Note: 以下のメンバーにメッセージを送信しました。" | html p
2324 sql="select coalesce(b.val, a.name) from
2325 (select name from user where rowid in ($uids)) a
2326 left join user_s b on a.name=b.name and b.key='gecos';"
2327 html pre<<EOF
2328 `query "$sql"`
2329 (送信者である $gecos さんも含まれます)
2330 EOF
2331 err SendDone: `echo $sql`
2332 fi
2333 elif [ x"$rm" = x"commission" ]; then
2334 grp_reg_adm $grid $usel
2335 elif [ x"$rm" = x"addteam" ]; then
2336 team=`getpar team|sed "s/'/''/g"` # for single quotation
2337 newteam=`echo "$team"|tr -d ,`
2338 if [ x"$team" != x"$newteam" ]; then
2339 echo "チーム名に使えない文字を除去しました" | html p
2340 team=newteam
2341 fi
2342 if [ -z "$team" -o x"$team" = x"なし" ]; then
2343 cat<<-EOF | html p
2344 有効なチーム名を入力してください。
2345 カンマだけ、「なし」という名前は使えません。
2346 EOF
2347 echo "有効なチーム名を入力してください。" | html p
2348 else
2349 grp_add_team $grid "$team" $usel
2350 fi
2351 elif [ x"$rm" = x"rmteam" ]; then
2352 if [ x"yes" = x"`getpar teamconfirm`" ]; then
2353 rmteam=`getpar rmteam|sed "s/'/''/g"`
2354 if [ -n "`query \"SELECT val FROM grp_mem_m WHERE\
2355 gname='$grp' AND user='$user' AND key='team'\
2356 AND val='$rmteam';\"`" ]; then
2357 grp_rm_team $grid "$rmteam" $usel
2358 else
2359 echo "所属していないチームの除去操作はできません。"|html p
2360 fi
2361 else
2362 echo "確認チェックなしなのでチーム除去しませんでした。"|html p
2363 fi
2364 fi
2365 fi
2366 # New entry
2367 sql="select /* Ahh, ugly SQL, I wanna fix... */
2368 case
2369 when (select user from grp_adm where
2370 gname=(select gname from grp where rowid=$grid)
2371 and user=a.name) is not null
2372 then 'k'
2373 else ''
2374 end || a.rowid||
2375 ','||a.gecos as NAME,
2376 (SELECT count(author) /* Put post count for scoring 2016-08-01 */
2377 FROM article NATURAL JOIN article_s
2378 WHERE blogid IN
2379 (SELECT id FROM blog_s
2380 WHERE key='owner'
2381 AND val=(SELECT gname FROM grp where rowid=$grid))
2382 AND author=a.name AND key='text')
2383 as POST,
2384 (SELECT group_concat(val, ',')
2385 FROM grp_mem_m
2386 WHERE gname='$grp' AND user=a.name AND key='team') as TEAM
2387 FROM
2388 gecoses a
2389 WHERE name in (select user from grp_mem where
2390 gname=(select gname from grp where rowid=$grid))
2391 ORDER by a.gecos;"
2392 ## err grpaction: "`echo \"$sql\"`"
2393 tf=$tmpd/title.$$
2394 echo "グループ[<a href=\"?grp+$grid\">$grp</a>]参加メンバーに対する操作" > $tf
2395 cmmsg="`cgi_radio rm commission id=\"cmadmin\"`<label
2396 for=\"cmadmin\">グループ管理者委任</label>
2397 <div><p>このグループでの全権を付与します。信頼できる人に託してください。
2398 </p></div>"
2399 excmsg="`cgi_radio rm yes id=\"conf\"`<label
2400 for=\"conf\">グループ登録解除</label>
2401 <div>本当に消します! `cgi_checkbox confirm yes` 確認
2402 <p>この操作による通知は本人に行きません。
2403 あらかじめ通知するか、登録解除してよい状況かしっかり確認してください。</p>
2404 </div>"
2405 # Get team list to which current user belongs into $hexteams
2406 myhexteams=$(hexteams "$grp" "$user")
2407 allhexteams=$(hexteams "$grp")
2408 if [ -n "$myhexteams" ]; then
2409 rmteammsg="`cgi_radio rm rmteam 'id=\"cmrmteam\"'`<label
2410 for=\"cmrmteam\">チーム属性除去</label>
2411 <div>チーム属性:`cgi_select_h rmteam \"2d2d2d\" $myhexteams`
2412 を除去します: `cgi_checkbox teamconfirm yes` 確認
2413 <p>この操作による通知は本人に行きません。
2414 あらかじめ通知するか、登録解除してよい状況かしっかり確認してください。</p>
2415 </div><!-- end of $rmteammsg -->
2417 fi
2418 b1='<label> <input type="checkbox" name="usel" value="'
2419 ba='<label class="admin"><input type="checkbox" name="usel" value="'
2420 #b2='"> <span>' b3='</span></label>'
2421 # | sed -e "s|^\(<TR><TD>\)k\([0-9]*\),\([^<]*\)|\1$ba\2$b2\3$b3|" \
2422 # -e "s|^\(<TR><TD>\)\([0-9]*\),\([^<]*\)|\1$b1\2$b2\3$b3|" \
2423 lnk='"> <span>\3</span></label> [<a href="?home+\2">HOME</a>]'
2424 cgi_form grpaction<<EOF \
2425 | sed -e "s|^\(<TR><TD>\)k\([0-9]*\),\([^<]*\)|\1$ba\2$lnk|" \
2426 -e "s|^\(<TR><TD>\)\([0-9]*\),\([^<]*\)|\1$b1\2$lnk|" \
2427 | _m4 -D_TITLE_="spaste(\`$tf')" \
2428 -D_SUBTITLE_="チェック後操作ボタン" \
2429 -D_FORM_="syscmd(cat)" -D_DUMPTABLE_="" \
2430 $layout/form+dump.m4.html
2431 <p>下でチェックした人を対象として:</p>
2432 <div class="foldtabs">
2433 `cgi_radio rm addteam 'id="cmteam"'`<label
2434 for="cmteam">同じチーム属性を付与</label>
2435 <div>チーム名:`cgi_text team "" 'id="inteam" list="teams"'`
2436 `cgi_datalist_h teams $allhexteams`
2437 </div>
2438 ${rmteammsg}
2439 `cgi_radio rm send id="sendmsg"`<label
2440 for="sendmsg">メッセージ送信</label>
2441 <div>
2442 `cgi_checkbox mkfrom yes 'id="mkfrom" checked'`<label for="mkfrom"
2443 >差出人を自分に(チェックを外すと相手が返事できない)</label><br>
2444 `cgi_textarea text "" cols=40`
2445 </div>
2446 ${isowner:+$cmmsg$excmsg}
2447 `cgi_radio rm close id="x"`<label for="x">×</label>
2448 </div>
2449 <h4>$grp 参加者一覧</h4>
2450 <table class="td2r">
2451 `sq $db -header -html "$sql"`
2452 </table>
2453 `cgi_hidden grp $grid`
2454 EOF
2456 crview4article() { # $1=rowid of blog, $2(optional)=extra SQL
2457 # Create TEMPORARY VIEW
2458 query<<EOF
2459 CREATE TEMPORARY VIEW writeusers AS
2460 SELECT DISTINCT author FROM article
2461 WHERE id in (
2462 select id from article where blogid=(select id from blog where rowid=$1)
2463 );
2464 CREATE TEMPORARY VIEW movablegroups AS
2465 SELECT g.rowid growid , g.gname
2466 FROM (SELECT grp.rowid, grp.gname FROM grp JOIN grp_mem gm
2467 ON grp.gname=gm.gname -- そのユーザが属している
2468 AND user='$user') g -- グループに絞る
2469 WHERE (SELECT author FROM writeusers
2470 EXCEPT
2471 SELECT user FROM grp_mem gm WHERE gm.gname = g.gname)
2472 IS NULL;
2473 $2
2474 EOF
2476 sql4readableblogs() {
2477 # Create view of blogs that can be readable to $user
2478 # Blog is readable when:
2479 # 1: blog owner is an user
2480 # 2: else, 2.1: owner-group where the $user belongs
2481 # 2.2: else, owner-group is not moderated
2482 # blog(id, author), blog_s(id, key='owner', val= ->owner)
2483 cat<<EOF ## | tee tmp/sql.out
2484 CREATE TEMPORARY VIEW readableblogs AS
2485 SELECT blog.rowid rid, id, author
2486 FROM blog
2487 NATURAL JOIN
2488 (SELECT id, val owner FROM blog_s WHERE key='owner') bs
2489 WHERE CASE WHEN (SELECT name FROM user where name=bs.owner) IS NOT NULL
2490 THEN 1 -- blog owner is an user, READABLE
2491 WHEN (SELECT val FROM grp_s
2492 WHERE gname=bs.owner AND key='regmode') = 'moderated'
2493 AND
2494 (SELECT user FROM grp_mem
2495 WHERE gname=bs.owner AND user='$user') IS NULL
2496 THEN 0
2497 ELSE 1
2498 END;
2499 EOF
2501 editheading() { # $1=rowid-of-heading
2502 rowid=${1%%[!A-Z0-9a-z_]*}
2503 if [ -z "$rowid" ]; then
2504 echo "話題番号が未指定です。" | html p
2505 return
2506 fi
2507 owner=`getvalbyid blog owner $rowid`
2508 title=`getvalbyid blog title $rowid`
2509 GF_ACTION="?blog" edittable $formdir/blog.def blog $rowid \
2510 | _m4 -D_TITLE_="修正" \
2511 -D_SUBTITLE_="[$title]@$owner" -D_DIARY_="" \
2512 -D_BLOGS_="" -D_DUMPTABLE_="" \
2513 -D_FORM_="syscmd(\`cat')" \
2514 $layout/html.m4.html $layout/form+dump.m4.html
2515 # Move to group
2516 if isuser "$owner"; then
2517 crview4article $rowid
2518 n=`query "SELECT count(*) FROM writeusers;"`
2519 ## err N=$n
2520 if [ $((n)) -gt 0 ]; then
2521 ## err ROWID=$rowid
2522 sql="SELECT growid || ':' || gname FROM movablegroups;"
2523 cat<<-EOF
2524 <div class="fold">
2525 `cgi_checkbox mv send id="mv"`<label
2526 for="mv">この話題をグループ所有に移動する</label>
2527 <div>
2528 <form action="?mvart" method="POST" enctype="multipart/form-data">
2529 移動先グループ:
2530 <select name="mv2grp">
2531 EOF
2532 query ".mode html"
2533 query<<-EOF |
2534 $sql
2535 .mode list
2536 EOF
2537 sed -e '/<\/TR>/d' -e 's,<TR>,,' -e 's,TD>,option>,g' \
2538 -e 's,n>\([0-9]*\):\(.*\)<,n value="\1">\2<,'
2539 cat<<-EOF
2540 </select>
2541 <p>(移動できるグループは、この「話題」に書き込んでいる人全てが
2542 そのグループに加入しているものに限られます)</p>
2543 <p>`cgi_checkbox cfm yes`<label>確認
2544 (この操作は元に戻すことができません)</label></p>
2545 `cgi_hidden blogrowid $rowid`
2546 `cgi_submit 移動`
2547 `cgi_reset Reset`
2548 </form>
2549 </div>
2550 </div>
2551 EOF
2552 fi
2553 # end of isuser "$owner"
2554 elif { hexteams=$(hexteams "$owner" ) # blog is of GROUP
2555 [ -n "$hexteams" ];}; then
2556 none="`echo なし|hexize`"
2557 cat<<-EOF
2558 <div class="fold">
2559 `cgi_checkbox mv2team send id="mv2team"`<label
2560 for="mv2team">この話題を以下のチームのものにする</label>
2561 <div><p>現在の所属チーム設定:
2562 `query "SELECT
2563 coalesce((SELECT val FROM blog_s
2564 WHERE id=(SELECT id FROM blog WHERE rowid=$rowid)
2565 AND key='team'),
2566 ':なし');"`</p>
2567 <form action="?mvart" method="POST" enctype="multipart/form-data">
2568 移動先チーム: `cgi_select_h mv2team $none $hexteams`
2569 <p>`cgi_checkbox cfm yes`<label>確認</label></p>
2570 `cgi_hidden blogrowid $rowid`<br>
2571 `cgi_submit 移動`
2572 `cgi_reset Reset`
2573 </form></div></div>
2574 EOF
2575 fi
2577 mvart() { # move diary to some group or team
2578 # or move blog of group to team which belong to the group
2579 blogrowid=`getpar blogrowid`
2580 cfm=`getpar cfm`
2581 ##### echo move blog:$blogrowid to $mv2grp | html p
2582 blogrowid=${blogrowid%%[!A-Z0-9a-z_]*} # Purify
2583 . ./s4-blog.sh
2584 if [ -z "$blogrowid" ]; then
2585 echo "無効な指定です(mvart)。" | html p
2586 return
2587 elif [ x"$cfm" != x"yes" ]; then
2588 echo "記事移動の確認にチェックがないので通常表示に戻ります。" | html p
2589 elif { mv2grp=`getpar mv2grp`
2590 mv2grp=${mv2grp%%[!A-Z0-9a-z_]*} # Purify
2591 [ -n "$mv2grp" ]; }; then
2592 crview4article $blogrowid
2593 ########## TRANSACTION BEGIN
2594 query "BEGIN;"
2595 n=`query "SELECT count(*) FROM writeusers;"`
2596 ## err Nwriteuser=$n
2597 if [ $((n)) -gt 0 ]; then
2598 query<<-EOF
2599 UPDATE blog_s SET val=(SELECT gname FROM grp WHERE rowid=$mv2grp)
2600 WHERE key='owner'
2601 AND id=(SELECT id FROM blog WHERE rowid=$blogrowid)
2602 AND $mv2grp IN (SELECT growid FROM movablegroups);
2603 EOF
2604 fi
2605 query "END;"
2606 ########## TRANSACTION END
2607 elif { mv2team=`getpar mv2team|sed "s/'/''/g"`
2608 [ -n "$mv2team" ];}; then
2609 # blog owner can move it to ANY team
2610 case "$mv2team" in
2611 'なし')
2612 cat<<-EOF
2613 DELETE FROM blog_s
2614 WHERE id=(SELECT id FROM blog WHERE rowid=$blogrowid)
2615 AND key='team';
2616 EOF
2617 ;;
2618 "") ;;
2619 *)cat<<-EOF
2620 BEGIN;
2621 REPLACE INTO blog_s(id, key, val)
2622 VALUES((SELECT id FROM blog WHERE rowid=$blogrowid),
2623 'team', '$mv2team');
2624 REPLACE INTO blog_s(id, key, val)
2625 VALUES((SELECT id FROM blog WHERE rowid=$blogrowid),
2626 'notify', 'all'); -- Change notify to all
2627 END;
2628 EOF
2629 esac | query
2630 fi
2631 blog_reply $blogrowid
2632 echo yes | html p
2634 editart() { # $1=article-rowid $2=blogrowid
2635 rowid=${1%%[!A-Z0-9a-z_]*}
2636 blogrowid=${2%%[!A-Z0-9a-z_]*}
2637 if [ -z "$rowid" -o -z "$blogrowid" ]; then
2638 echo "表示する記事番号が未指定です。" | html p
2639 return
2640 fi
2641 owner=`getvalbyid blog owner $blogrowid`
2642 title=`getvalbyid blog title $blogrowid`
2643 author=`getvalbyid article author $rowid`
2644 ## err EDITart: owner=$owner, author=$author
2645 if isgrpowner $user $owner; then
2646 : EDIT OK
2647 elif [ x"$owner" != x"$user" -a x"$author" != x"$user" ]; then
2648 echo "本人か所有者しか編集できません." | html p
2649 return
2650 fi
2651 aid=`query "select id from article where rowid=$rowid;"`
2652 tmpout=$tmpd/editart.$$.out
2653 GF_ACTION="?replyblog+$blogrowid#$aid" \
2654 edittable $formdir/article.def article $rowid \
2655 > $tmpout
2656 rm -f /tmp/editart.out
2657 # Cannot use pipelining to m4 with genform() because of stdin stack
2658 _m4 -D_TITLE_="コメントの修正" -D_DIARY_="" \
2659 -D_FORM_="syscmd(cat $tmpout)" \
2660 -D_SUBTITLE_="`gecos $owner`の「$title」" \
2661 -D_BLOGS_= -D_DUMPTABLE_= \
2662 $layout/html.m4.html $layout/form+dump.m4.html
2664 send2mem() {
2665 rowid=`getpar grp`
2666 if [ -z "$rowid" ]; then
2667 echo "グループが未指定です。" | html p
2668 return
2669 fi
2670 message=`getpar message`
2671 if [ -z "$message" ]; then
2672 echo "文章を入れてください。" | html p
2673 return
2674 fi
2675 grp=`getgroupbyid $rowid`
2676 members=`collectemail $grp`
2677 # smail rcpt subj (file)
2678 smail "$members" "グループ $grp 宛メッセージ(from `gecos $user`)" <<EOF
2679 $urlbase?grp+$rowid
2680 グループ $grp に所属する
2681 `gecos $user` さんよりメッセージ:
2683 $message
2684 EOF
2685 cat<<EOF
2686 <p>以下の宛先に送信しました。</p>
2687 <pre>
2688 $members
2689 </pre>
2690 <p><a href="?grp+$rowid">グループ $grp</a>に戻る。</p>
2691 EOF
2693 joingrpadmit() {
2694 # $1=yes/no $2=session-key
2695 if [ -z "$2" ]; then
2696 echo "bye bye" | html p; return
2697 fi
2698 t_usr=`session=$2 getpar user`
2699 t_grp=`session=$2 getpar group`
2700 ## err joingrpadmit: t_usr=$t_usr, t_grp=$t_grp
2701 _m4 -D_TITLE_="joingrp" $layout/html.m4.html
2702 if [ -z "$t_usr" -o -z "$t_grp" ]; then
2703 echo "無効な加入依頼です。" | html p
2704 echo "有効期限が切れたか、
2705 他の管理者がいる場合は処理済みの可能性があります。" | html p
2706 return
2707 fi
2708 if ! isgrpowner "$user" $t_grp; then
2709 echo "グループ管理者のみの機能です。" | html p; return
2710 fi
2711 case $1 in
2712 yes) joingrp "$t_grp" "$t_usr" yes ;;
2713 no) joingrp "$t_grp" "$t_usr" no ;;
2714 *)
2715 echo "無効な指定です($1)。" | html p
2716 return ;;
2717 esac
2718 gid=$(query "select rowid from grp where gname=`sqlquote $t_grp`;")
2719 rcpts="`getgroupadminmails $t_grp` $user"
2720 ## err admit: msgdir=$msgdir, rcpts="["$rcpts"]"
2721 body="グループ <a href=\"?grp+$gid\">$t_grp</a>
2722
2723 $t_usr
2724 `[ x$1 = xyes ] && echo 'を追加' || echo 'の解除操作を'`
2725 しました。"
2726 (echo "$body"; echo; echo "$url?grp+$gid") | smail "$rcpts" "joingrp $1"
2727 query "delete from session where id='$2';"
2728 echo "$body" | html p
2731 joingrprequest() {
2732 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
2733 jss="joingrp-`date +%s`-`genrandom 12`"
2734 addsession $jss +${memoplimitdays}days
2735 query "replace into par values('$jss', 'group', 'string', `sqlquote $1`),
2736 ('$jss', 'user', 'string', `sqlquote $user`);"
2737 smail "$(collectemail `getgroupadmins $1`)" "Join request to $1"<<EOF
2738 $url
2739 $user さんから
2740 グループ $1
2741 に加入依頼がありました。
2743 承認する:
2744 $urlbase?joingrpadmit+yes+$jss
2746 白紙に戻す:
2747 $urlbase?joingrpadmit+no+$jss
2748 EOF
2749 echo "管理者に加入依頼を出しました。
2750 ${memoplimitdays}日以内に加入承認操作がされれば加入できますが、
2751 グループ運用方針に懸かることですので直接の問い合わせが重要です。" | html p
2753 joingrp() {
2754 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
2755 ## err joingrp: \$1=$1 \$2=$2 \$3=$3 \$4=$4
2756 if isgrpowner "$user" "$1"; then
2757 isowner="yes"
2758 elif [ -n "$5" ]; then
2759 isowner="yes"
2760 else
2761 isowner=""
2762 fi
2763 ## err jg:isgrpowner: isowner="$isowner"
2764 if [ -n "$isowner" ]; then
2765 : # GROUP OWNER CAN DO EVERYTHING ABOUT REGISTRATION/RETIREMENT
2766 elif [ x"$2" != x"$user" ]; then # if user is not login user
2767 echo "本人か、グループ管理者しか加入操作はできません。" | html p
2768 return
2769 elif [ x"$3" = x"no" ]; then
2770 : # Do not pursue those who leave
2771 elif [ x"$3" = x"yes" ] && ismember "$user" "$grp"; then
2772 : # Member can change own email address for the joining moderated group
2773 else # adding user is $user itself
2774 case `getgroupattr $1 regmode` in
2775 moderated)
2776 joingrprequest "$@" # Request only
2777 return
2778 ;;
2779 *)
2780 ;;
2781 esac
2782 fi
2783 qgname=`sqlquote $1`
2784 cond="where gname=$qgname and user='$2'"
2785 if [ x"$3" = x"yes" ]; then
2786 query "replace into grp_mem values($qgname, '$2');"
2787 if [ -n "$4" ]; then
2788 if msg=`emaildomaincheck "$4"`; then
2789 query "replace into grp_mem_s values($qgname, '$user', 'email', \
2790 'string', '$4', NULL);"
2791 else
2792 echo $msg
2793 fi
2794 else
2795 query "delete from grp_mem_s $cond and key='email';"
2796 fi
2797 if [ -n "$5" ]; then # as ADMIN
2798 # Coming here means newly created group
2799 sql="select case\
2800 when (select count(*) from grp_mem where gname=$qgname)=1\
2801 then (select user from grp_mem\
2802 where gname=$qgname and user='$user')\
2803 else '' end; "
2804 err NewGrpChk: $sql
2805 if [ -n "`query \"$sql\"`" ]; then
2806 ## err ADMIN: "replace into grp_adm values($qgname, '$user');"
2807 query "replace into grp_adm values($qgname, '$user');"
2808 fi
2809 fi
2810 else
2811 query "delete from grp_mem $cond;
2812 delete from grp_mem_s $cond;
2813 delete from grp_mem_m $cond;"
2814 fi
2816 grp_add_team() (
2817 # $1=grp-rowid $2=team $3...=user-rowid(s)
2818 grp=`getgroupbyid $1`
2819 team=$2; shift; shift
2820 [ -z "$grid" -o -z "$team" -o -z "$1" ] && return
2821 { echo "BEGIN;"
2822 for user; do
2823 echo "REPLACE INTO grp_mem_m(gname, user, key, type, val) VALUES(\
2824 '$grp',\
2825 (SELECT name FROM user WHERE rowid=$user),\
2826 'team', 'string', '$team');"
2827 done
2828 echo "END;"
2829 } | query
2831 grp_rm_team() (
2832 # $1=grp-rowid $2=team $3...=user-rowid(s)
2833 grid=$1
2834 qgrp=$(sqlquote "`getgroupbyid $grid`")
2835 team=$2; shift; shift
2836 [ -z "$grid" -o -z "$team" ] && return
2837 { echo "BEGIN;"
2838 for user; do
2839 echo "DELETE FROM grp_mem_m\
2840 WHERE gname=$qgrp \
2841 AND user=(SELECT name FROM user WHERE rowid=$user)\
2842 AND key='team' AND val='$team';"
2843 done
2844 cat<<-EOF
2845 DELETE FROM blog_s
2846 WHERE rowid=(
2847 SELECT rowid
2848 FROM blog_s a
2849 WHERE key='team'
2850 AND id IN (SELECT id FROM blog_s WHERE key='owner' AND val=$qgrp)
2851 AND NOT EXISTS (SELECT * FROM grp_mem_m
2852 WHERE key='team' AND val=a.val -- a.val=team
2853 AND gname = (SELECT val FROM blog_s b
2854 WHERE a.id=b.id AND key='owner')
2855 ));
2856 EOF
2858 echo "END;"
2859 } | query
2861 grp_reg_adm() {
2862 # $1=grp-rowid $2...=user-rowid
2863 grid=$1
2864 grp=`getgroupbyid "$1"`
2865 if [ -z "$grp" ]; then
2866 echo "無効なグループIDです" | html p; return
2867 fi
2868 if ! isgrpowner $user "$grp"; then
2869 echo "$grp グループの管理者しかこの操作はできません。" | html p; return
2870 fi
2871 shift
2872 for urid; do
2873 newadm=`query "select name from user where rowid=$urid;"`
2874 if [ -z "$newadm" ]; then
2875 echo "指定ユーザIDがおかしいようです。" | html p; return
2876 fi
2877 err GRP_reg_adm: "replace into grp_adm values(`sqlquote $grp`, '$newadm');"
2878 err ismember $newadm $grp
2879 if ismember $newadm $grp; then
2880 # OK, go ahead
2881 getgname="(select gname from grp where rowid=$grid)"
2882 query "replace into grp_adm values($getgname, '$newadm');"
2883 # confirm insertion
2884 sql="select * from grp_adm where gname=$getgname and user='$newadm'"
2885 if [ -n "`query \"$sql;\"`" ]; then
2886 echo "追加完了: $newadm" | html p
2887 else
2888 echo "追加失敗($1 $urid)" | html p
2889 fi
2890 fi
2891 showgroup $grid
2892 done
2894 dumptable() {
2895 # $1=mode $2=Table $3=column-list-of-*_s(defaults to *) $4=conditions(if any)
2896 # textのフィールドだけ全てダンプにしたほうがいいか
2897 # $DT_VIEW sets link
2898 # 6/17の次: editリンクじゃなくてスレッドVIEWリンクでいいんちゃう?
2899 ### elink="<a href=\"$myname?edittable+$2+\\2\">EDIT</a>"
2900 VIEW=${DT_VIEW-replyblog}
2901 if [ -n "$VIEW" ]; then
2902 dvlink=" <a href=\"$myname?$VIEW+\\2\\3\">VI</a><a href=\"$myname?$VIEW+\\2#bottom\">EW</a>"
2903 fi
2904 # $DT_CHLD=ChildTable:BindColumn
2905 if [ -n "$DT_CHLD" ]; then
2906 _t=${DT_CHLD%:*} _i=${DT_CHLD#*:}
2907 cntall="(select count($_i) from $_t where $_i=a.id)"
2908 # XXX: Dirty workaround for slow subquery of acclog
2909 presql="CREATE TEMPORARY TABLE IF NOT EXISTS myacclog AS
2910 SELECT * FROM acclog WHERE user='$user' and tbl='$2';"
2911 cntnew="(select count(val) from ${_t}_s where key='ctime' \
2912 and id in (select id from $_t where $_i=a.id) \
2913 and val > coalesce((select time from myacclog where \
2914 tblrowid=a.rowid),\
2915 '1970-01-01'))"
2916 cnt="$cntnew as '新着', $cntall as '総数',"
2917 dt_class=" td2r td3r dumpblogs"
2918 fi
2919 # Construct join expression
2920 eav="" scols=""
2921 pk=`gettblpkey $2`
2922 substr=${dumpcollen:+"substr(val, 0, $dumpcollen)"}
2923 substr=${substr:-val}
2924 for col in ${3:-`gettbl_s_cols $2`}; do
2925 case $col in
2926 gecos) scols="$scols${scols:+, }${col#}"
2927 continue ;; # built-in column name
2928 *:*) col=${col%:*} as=${col#*:} ;;
2929 *) as=${col} ;;
2930 esac
2931 eav=$eav${eav:+,}" max(case key when '$col' then $substr end) as $as"
2932 scols="$scols${scols:+, }b.$as"
2933 done
2934 #case author when '$user' then a.rowid else '---' end as ID,
2935 sql=${DT_SQL:-"select \
2936 a.rowid as LINK,\
2937 $cnt\
2938 $scols from $2 a left join\
2939 (select $pk,$eav,
2940 max(case key when 'owner'
2941 then (SELECT gecos FROM gecoses WHERE name=val) END) as gecos
2942 from ${2}_s c group by $pk) b on a.$pk=b.$pk $4;"}
2943 ## err dt:SQL="`echo \"$presql$sql\"|tr -d '\n'`"
2944 cat<<EOF | sed "s,\(<TR><TD>\)\([1-9][0-9]*\)\(#[0-9a-fxs]*\)*</TD>,\1$elink$dvlink</TD>,"
2945 <div> <!-- for folding by check button (s4-funcs.sh:dumptable()) -->
2946 <div class="dumptable">
2947 <table class="b$dt_class">
2948 `sq -header -cmd ".mode $1" $db "$presql$sql"`
2949 </table>
2950 </div> <!-- dumptable -->
2951 </div> <!-- for folding by check button (s4-funcs.sh:dumptable()) -->
2952 EOF
2955 par2table() (
2956 # copy current parameters of par into destination table
2957 # $1=definition-file
2958 # Using $user and $session
2959 # Return value:
2960 # 0: Stored successfully
2961 # 1: Insufficient fillings
2962 # 2: No permission to modify the record
2963 # 3: Invalid rowid
2964 # 4: SUCCESS to delete
2965 # 5: Stop deletion for lack of confirm check
2966 # 6: Password length too short
2967 # 7: Password mismatch
2968 # 8: Old password incorrect
2969 rowid=`getpar rowid`
2970 if [ ! -e $1 ]; then
2971 echo "テーブル定義ファイルが見付かりません" | html p
2972 exit 1
2973 fi
2974 tbl=${1%.def}
2975 tbl=${tbl##*/}
2976 if [ -n "$rowid" ]; then # Modify existing entry
2977 if [ x"$tbl" = x"user" ]; then
2978 rowowner=`query "select name from $tbl where rowid=$rowid;"`
2979 elif [ x"$tbl" = x"grp" ]; then
2980 sql="select gname from $tbl where rowid=$rowid;"
2981 ##err p2t:grp:q $sql
2982 isgrpowner $user "`query $sql`" && rowowner=$user
2983 else
2984 rowowner=`query "SELECT owner FROM $tbl WHERE rowid=$rowid;"`
2985 rowowner=${rowowner:-`query "select author from $tbl
2986 where rowid=$rowid;"`}
2987 fi
2988 ### err rowowner=$rowowner
2989 if [ x"$user" != x"$rowowner" ]; then
2990 echo "他人のレコードはいじれないの" | html p
2991 return 2
2992 elif [ -z "$rowowner" ]; then
2993 echo "指定したレコードはないみたい" | html p
2994 return 3
2995 fi
2996 rm=`getpar rm` cfm=`getpar confirm`
2997 # Editing existent entry
2998 if [ x"$rm" = x"yes" ]; then
2999 if [ x"$rm$cfm" = x"yesyes" ]; then
3000 query "delete from $tbl where rowid=$rowid;"
3001 return 4
3002 else
3003 echo "消去確認のチェックがないので消さなかったの..." | html p
3004 return 5
3005 fi
3006 fi
3007 fi
3009 ts=${tbl}_s tm=${tbl}_m val="" pval="" formaster=""
3010 if [ -n "$rowid" ]; then
3011 # Update of existing record
3012 for col in `gettblcols $tbl`; do
3013 val=`getparquote $col`
3014 [ -z "$val" ] && continue
3015 ## err query "update $tbl set $col=$val where rowid=$rowid"
3016 ## XX: THIS IS DIRTY hack to ensure non-foreign key in blog_s
3017 sql="update $tbl set $col=$val where rowid=$rowid;"
3018 if [ x"$tbl" = x"grp" -a x"$col" = x"gname" \
3019 -o x"tbl" = x"user" -a x"$col" = x"name" ]; then
3020 ## User name cannot be changed with interface provided with this
3021 ## script. But we offer the trigger to change owner user
3022 ## of blog_s table.
3023 #err "select quote($col) from $tbl where rowid=$rowid;"
3024 old=`query "select quote($col) from $tbl where rowid=$rowid;"`
3025 cat<<-EOF | query
3026 -- Here we cannot use BEGIN-COMMIT because groupupdate()
3027 -- should use EXCLUSIVE transaction outside of this.
3028 SAVEPOINT par2table;
3029 $sql
3030 update blog_s set val=$val
3031 where key='owner' and val=$old;
3032 RELEASE SAVEPOINT par2table;
3033 EOF
3034 ## XX: DIRTY Hack Ends here
3035 ## We should keep blog's owner as a single column which has
3036 ## foreign key constraint with primary key of grp/user.
3037 else
3038 query "$sql"
3039 fi
3040 done
3041 # Then, set up $pval for further insertion of tbl_s and tbl_m
3042 for col in `gettblpkey $tbl`; do
3043 val=`query "select $col from $tbl where rowid=$rowid;"|sed -e 's/\"/\"\"/g'`
3044 pval="$pval${pval:+, }\"$val\""
3045 done
3046 else
3047 # New entry
3048 # Generate values() for primary keys
3049 for col in `gettblpkey $tbl`; do
3050 # Genuine primary keys for _m and _s
3051 val=`getvalquote $tbl $col`
3052 [ -z "$val" ] && continue
3053 pval="$pval${pval:+, }$val"
3054 done
3055 ##err pval=$pval
3056 for col in `gettblfkey $tbl`; do
3057 # args for values() to insertion into master table
3058 val=`getvalquote $tbl $col`
3059 [ -z "$val" ] && continue
3060 formaster=$formaster"${formaster:+, }$val"
3061 done
3062 formaster="$pval${formaster:+, }$formaster"
3063 ## err formaster=$formaster
3064 if [ -z "$formaster" ]; then
3065 echo "項目を全て埋めてください" | html pre
3066 return 1
3067 fi
3068 ## err "replace into $tbl values($formaster);"
3069 query "replace into $tbl values($formaster);"
3070 ## Insertion to master table, done
3071 fi
3073 for kt in s m; do
3074 tb2=${tbl}_$kt
3075 for col in `gettbl_${kt}_cols $tbl`; do
3076 ptype=`getpartype $col "limit 1"`
3078 # First, check update of existing entries in _m
3079 if [ $kt = m ]; then
3080 # sessID|address.1.22|string|Somewhere-x.y.z
3081 sql=""
3082 ##err dots from query "select var from par where var like '$col.%';"
3083 for v in `query "select var from par where var like '$col.%';"`; do
3084 # v=address.1.22
3085 st_rowid=${v##*.}
3086 origcol=${v%%.*} # original column derived from
3087 ##err Updating for $v st_rowid=$st_rowid, partype=`getpartype $v`
3088 ##case `getpartype $v` in
3089 ## err CASE `gettbl_coltype $tbl/$origcol` in
3090 ## err edit flag = `getpar action.$v`
3091 case `getpar action.$v` in
3092 rm)
3093 if [ x`getpar confirm.$v` = x"yes" ]; then
3094 newsql="delete from $tb2"
3095 else
3096 echo "削除確認未チェック" | html p
3097 fi ;;
3098 edit)
3099 case `gettbl_coltype $tbl/$origcol` in
3100 image|document|binary)
3101 file=$tmpd/`getparfilename $v`
3102 ## err type=file=$file
3103 [ -z "$file" ] && continue
3104 bn=`sqlquotestr "${file##*/}"`
3105 bin="X'"$(hexize "$file")"'"
3106 ct=`file --mime-type - < "$file" |cut -d' ' -f2`
3107 type=\"file:$ct\"
3108 newsql="update $tb2 set val=$bn, type=$type, bin=$bin"
3109 cachedir=`getcachedir "$tbl/$rowid"`
3110 err getcache tbl/rowid=$tbl/$rowid, rm -r $cachedir
3111 rm -rf $cachedir
3112 ;;
3113 *)
3114 newsql="update $tb2 set val=(select val from par where var \
3115 like '$col.%.$st_rowid')"
3116 ;;
3117 esac
3118 ;;
3119 *) # maybe "keep", do not modify value
3120 continue
3121 ;;
3122 esac
3123 # err newsql=$newsql
3124 sql=$sql$nl"$newsql where rowid=$st_rowid;"
3125 done
3127 if [ x"$bin" = x"NULL" ]; then
3128 ## err repl:normal sql=`echo $sql`
3129 query "$sql
3130 delete from $tb2 where type='string' and val='';"
3131 ## err repl:normal done
3132 else
3133 sqlfile="$tmpd/sqlf.$$"
3134 echo "$sql" > $sqlfile
3135 ## err repl:sqlfile=`ls -lF $sqlfile`
3136 query ".read $sqlfile"
3137 ## err repl:done
3138 fi
3139 # Rest of kt==m: set multiple mode
3140 nr=`getparcount $col`
3141 else
3142 nr=1 # for kt==s, number of records is 1
3143 fi
3145 i=0
3146 while [ $i -lt $nr ]; do
3147 limit="limit 1 offset $i"
3148 i=$((i+1)) # increase beforehand against continue
3149 val=`getvalquote $tbl $col "$limit"`
3150 [ -z "$val" -o x"$val" = x'""' -o x"$val" = x"NULL" ] && continue
3151 ## err $col=$val
3152 bin=NULL
3153 ## err partype$col=`getpartype $col "$limit"`
3154 case $ptype in
3155 file) file=$tmpd/`getparfilename $col "$limit"`
3156 ## err parfile-$col=$file
3157 [ -z "$file" ] && continue
3158 bin="X'"$(hexize "$file")"'"
3159 ct=`file --mime-type - < "$file"|cut -d' ' -f2`
3160 type=\"file:$ct\" ;;
3161 "*"*) continue ;; # foreign table
3162 *) type=\"string\" ;;
3163 esac
3164 case `gettbl_coltype $tbl/$col` in
3165 password) # special care for password
3166 # name={password,pswd1,pswd2}
3167 p1=`getpar pswd1 "$limit"`
3168 if [ -z "$p1" ]; then
3169 continue # SKIP password setting, if p1 is empty
3170 else
3171 pswd=`getpar pswd "$limit"` p2=`getpar pswd2 "$limit"`
3172 ## err pswd=$pswd
3173 if pwcheck "$pswd"; then
3174 if [ x"$p1" = x"$p2" ]; then
3175 case "$p1" in
3176 ??????????*) ;;
3177 *) echo "パスワードは10字以上にしてください。" | html p
3178 return 6;;
3179 esac
3180 val="\"`echo $p1|mypwhash`\""
3181 else
3182 echo "2つの新パスワード不一致" | html p
3183 return 7
3184 fi
3185 else
3186 echo "旧パスワード違います" | html p
3187 return 8
3188 fi
3189 fi
3190 ;;
3191 esac
3192 ## err p2t: "replace into $tb2 values($pval, \"$col\", $type, $val, bin...);"
3193 #query "replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
3194 sql="replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
3195 if [ x"$bin" = x"NULL" ]; then
3196 ## err Normal-query: `echo $sql`
3197 query "$sql"
3198 else
3199 sqlfile="$tmpd/query.$$"
3200 echo "$sql" > $sqlfile
3201 ## err sqlfile=`ls -lF $sqlfile`
3202 query ".read $sqlfile"
3203 fi
3204 ## err p2t done
3205 done
3206 done
3207 done
3208 return 0
3209 ##err donee
3211 genform() {
3212 # $1 = form definition file
3213 # $2, $3 (optional)= table name and ROWID
3214 # If $GF_VIEWONLY set and nonNull, output values without form
3215 # If $GF_ARGS set, use it as content-strings in the form
3216 # If $GF_OWNER set, use it as value of name="owner"
3217 # If $GF_STAGE set, use it as value of name="stage"
3218 forms="" hiddens="" rowid=$3
3219 if [ ! -e "$1" ]; then
3220 echo "そのようなデータベースはないようです($2)。" | html p
3221 return
3222 elif [ -n "$2" ]; then
3223 rec=`query "select * from $2 where rowid='$rowid';"`
3224 if [ -z "$rec" ]; then
3225 pk=`gettblpkey $2`
3226 ###rec=`sq $db "select rowid from $2 where $pk='$rowid'"`
3227 rec=`query "select rowid from $2 where $pk='$rowid';"`
3228 rowid=$rec
3229 rec=$3
3230 fi
3231 if [ -z "$rec" ]; then
3232 echo "そんなレコードはないみたいね..." | html p
3233 return
3234 fi
3235 fi
3236 if [ -z "$GF_VIEWONLY" ]; then
3237 rm='<input id="rm" name="rm" type="checkbox"
3238 value="yes"><label for="rm">このエントリの削除</label>
3239 <span>ほんとうに消しますよ(確認)!
3240 <input name="confirm" type=checkbox value="yes">はい</span>'
3241 fi
3242 # Image Cache dir
3243 ## err genform: getcache=$2/$rowid
3244 td=`getcachedir "$2/$rowid"`
3245 while IFS=: read prompt name keytype type args; do
3246 [ -z "${prompt%%\#*}" ] && continue # skip comment line(#)
3247 sp="${args:+ }"
3248 form="" val=""
3249 if [ -n "$rowid" ]; then
3250 # err genform2a: Seeking for "$2.$name, type=$type"
3251 rawval=`getvalbyid $2 $name $rowid $td`
3252 val=`echo "$rawval"|htmlescape`
3253 ## err genform3a: getvalbyid $2 $name $rowid $td
3254 ## err genform3b: val="[$val]" type="$type"
3255 fi
3256 if [ -n "$GF_VIEWONLY" ]; then
3257 is_hidden "$2" "$name" && continue
3258 fi
3259 case "$type" in
3260 text*)
3261 cgiform=cgi_multi_$type
3262 if [ -s $td/$name.count -a -n "$val" ]; then
3263 form=`$cgiform $name $td`
3264 val=$(echo "$val"|
3265 while read fn; do
3266 echo "<tr><td>`cat $td/$fn|htmlescape|hreflink`
3267 </td></tr>$nl"
3268 done)
3269 val="<table>$nl$val$nl</table>"
3270 else
3271 #form="<input name=\"$name\" value=\"$val\" type=\"$type\"$sp$args>$nl"
3272 form=`cgi_$type $name "$rawval" "$args"`
3273 fi
3274 ;;
3275 [Rr][Aa][Dd][Ii][Oo])
3276 fh="<label><input type=\"radio\" name=\"$name\""
3277 form="`echo $args|sed -e \
3278 \"s,\([^ =][^=]*\)=\([^= ][^= ]*\),$fh value=\\"\2\\">\1</label>,g\"`"
3279 ;;
3280 [Cc][Hh][Ee][Cc][Kk][Bb][Oo][Xx])
3281 form="<label><input type=\"checkbox\" name=\"$name\" value=\"${args#*=}\">${args%=*}</label>"
3282 ;;
3283 [Ss][Ee][Ll][Ee][Cc][Tt])
3284 fh="<select name=\"$name\">$nl"
3285 form=$(for l in $args; do
3286 echo "<option value=\"${l#*=}\">${l%=*}</option>"
3287 done)
3288 if [ -n "$val" ]; then
3289 form=`echo $form|sed -e "s,\(value=.$val.\),\\1 selected,"`
3290 fi
3291 form="$fh$form</select>"
3292 ;;
3293 [Ii][Mm][Aa][Gg][Ee]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Bb]inary)
3294 if [ -s $td/$name.count ]; then
3295 form=`cgi_multi_file $name $td "$args"`
3296 if [ -n "$val" ]; then
3297 hrfb="$myname?showattc+$2_m"
3298 val=$(echo "$rawval" \
3299 | while read fn; do
3300 data=`percenthex "$td/$fn"`
3301 #ct=`cat $td/$fn.content-type`
3302 ct=`file --mime-type - < "$td/$fn"|cut -d' ' -f2`
3303 ri=`cat "$td/$fn.rowid"`
3304 ## err fn=$fn, name=$name, ri=$ri; ls -lF "$td/" 1>&3
3305 #imgsrc="<img src=\"data:$ct,$data\">"
3306 #echo "<a href=\"$hrfb+$ri\">$imgsrc</a><br>"
3307 iconhref "$td/$fn" "$hrfb+$ri" ""
3308 done)
3309 fi
3310 else
3311 form="<input type=\"file\" name=\"$name\" $args>"
3312 if [ -n "$val" ]; then
3313 imgs=$(echo "$rawval"\
3314 |while read fn;do
3315 data=`percenthex "$td/$fn"`
3316 echo "<img src=\"data:image/png,$data\">$fn<br>"
3317 done)
3318 form=$form"<br>$imgs"
3319 val=$imgs # 2015-06-15
3320 else
3321 form="<input type=\"file\" name=\"$name\" $args>"
3322 fi
3323 fi
3324 ;;
3325 [Hh][Ii][Dd][Dd][Ee][Nn])
3326 if [ -n "$GF_STAGE" -a x"$name" = x"stage" ]; then
3327 args="value=\"$GF_STAGE\""
3328 fi
3329 form="<input type=\"hidden\" name=\"$name\" $args>"
3330 prompt='' # Remove prompt
3331 ;;
3332 [Aa][Uu][Tt][Hh][Oo][Rr])
3333 [ -n "$GF_VIEWONLY" ] && continue
3334 form="<input type=\"hidden\" name=\"author\" value=\"$user\">"
3335 prompt="" ;;
3336 [Oo][Ww][Nn][Ee][Rr])
3337 [ -n "$GF_VIEWONLY" ] && continue
3338 val=${GF_OWNER:-$val}
3339 val=${val:-$user}
3340 form="<input type=\"hidden\" name=\"owner\" value=\"$val\">"
3341 prompt="" ;;
3342 [Uu][Ss][Ee][Rr])
3343 # XXX: is null $user ok?
3344 #form="<input type=\"hidden\" name=\"user\" value=\"$user\">"
3345 [ -n "$GF_VIEWONLY" ] && continue
3346 form="$user"
3347 ;;
3348 [Pp]assword)
3349 [ -n "$GF_VIEWONLY" ] && continue
3350 form="`cgi_passwd`"
3351 val=""
3352 ;;
3353 [Ss][Ee][Rr][Ii][Aa][Ll]|[Ss][Tt][Aa][Mm][Pp])
3354 [ -n "$GF_VIEWONLY" ] && continue
3355 if [ -z "$rowid" ]; then
3356 val=`genserial`
3357 fi
3358 form="<input type=\"hidden\" name=\"$name\" value=\"$val\">"
3359 prompt="" ;;
3360 [Ss][Ee][Ss][Ss][Ii][Oo][Nn])
3361 prompt=""
3362 ;;
3363 parent|path|blog*)
3364 prompt=""
3365 ;;
3366 "*"*)
3367 tail=$tail"``"
3368 continue ;;
3369 esac
3370 if [ -n "$prompt" ]; then
3371 if [ -n "${GF_VIEWONLY}" ]; then
3372 form=$val
3373 else
3375 fi
3376 forms=$forms" <tr class=\"$name\"><th>$prompt</th><td>$form</td></tr>$nl"
3377 else
3378 hiddens=$hiddens$nl"$form"
3379 fi
3380 done < $1
3381 # enctype="multipart/form-data"
3382 cat<<EOF
3383 <form action="${GF_ACTION:-$myname}" method="POST" enctype="multipart/form-data">
3384 ${rowid:+$rm}
3385 <table class="b $2">
3386 $forms
3387 </table>$hiddens
3388 ${GF_STAGE:+`cgi_hidden stage $GF_STAGE`}
3389 ${rowid:+<input type="hidden" name="rowid" value="$rowid">}
3390 EOF
3391 if [ -z $GF_VIEWONLY ]; then
3392 cat<<EOF
3393 <input type="submit" name="sub" value="OK">
3394 <input type="reset" name="res" value="Reset">
3395 EOF
3396 fi
3397 cat<<EOF
3398 $GF_ARGS</form>
3399 $tail
3400 EOF
3402 edittable() {
3403 # $1=form-def $2=table $3 rowid
3404 genform "$@"
3406 viewtable() {
3407 GF_VIEWONLY=1 genform "$@"
3409 showattc() {
3410 # $1=table_m $2=rowid &optional $3=RawFlag
3411 ## err \$1=$1 \$2=$2 \$3=$3
3412 if ! isfilereadable $user $1 $2; then
3413 contenttype; echo
3414 echo "このファイルは管理者のみしか見られません" | html p
3415 putfooter; exit
3416 fi
3417 idir=`umask 002; mktempd` || exit 1
3418 # tmpfiles=$tmpfiles"${tmpfiles+ }$idir"
3419 bin=$idir/$myname-$$.bin
3420 sql="select quote(bin) from $1 where rowid='$2';"
3421 ## err showattc: sql: $sql
3422 sq $db "$sql" | unhexize > $bin
3423 tv=`query "select type||'//'||val from $1 where rowid='$2';"`
3424 type=${tv%//*} fn=${tv#*//}
3425 ## err tv=$tv type=$type fn=$fn, tp2=${tv%\|*}
3426 ct=${type#file:}
3427 case $ct in # all text/* changed to text/plain
3428 text/*)
3429 charset=`nkf -g $bin|cut -d' ' -f1`
3430 case $charset in
3431 ASCII*) charset="" ;;
3432 esac
3433 if [ -z "$3" ]; then
3434 ct="text/html${charset:+; charset=$charset}"
3435 link="?showattc+$1+$2+raw"
3436 cat $bin | htmlescape \
3437 | sed 's,^,<span></span>,' \
3438 | _m4 -D_TITLE_="$fn" -D_CONTENT_TYPE_="$ct" \
3439 -D_LINK_="$link" \
3440 -D_BODY_="syscmd(\`cat')" $layout/pretty.m4.txt
3441 exit $?
3442 fi
3443 ct="text/plain${charset:+; charset=$charset}"
3444 ;;
3445 esac
3446 contenttype "$ct"
3447 echo "Content-Disposition: filename=\"$fn\""
3448 echo "Content-Length: " `cat $bin | wc -c`; echo
3449 #echo "Content-Type: " ${type#file:}; echo
3450 cat $bin
3453 # Some default stupid handler on CGI values
3455 default_storedb() {
3456 # ARG: $1=table-def-file
3457 # RET: $tbl=table-name, $col=mail-column, $cols=columns
3458 tbl=`basename $1`
3459 tbl=${tbl%.def}
3460 cols="`grep :text $1|cut -d: -f2`"
3461 col=`echo "$cols"|head -1`
3462 vcol=`getpar $col`
3463 err default0: \$1=$1 col=$col cols="[$cols]" vcol=$vcol
3464 if [ -n "$vcol" ]; then
3465 par2table $1
3466 else
3467 return 2 # No insertion occurred
3468 fi
3471 default_view() { # $1=def-file
3472 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
3473 ## DT_VIEW="edittable+$tbl" dumptable html $tbl "name memo file" \
3474 default_storedb "$@"
3475 query "select rowid from $tbl order by rowid desc;" \
3476 | while read rowid; do
3477 viewtable $1 $tbl $rowid
3478 done | _m4 -D_TITLE_="$tbl" \
3479 -D_FORM_="`genform $1`" \
3480 -D_DUMPTABLE_="syscmd(cat)" \
3481 $layout/html.m4.html $layout/form+dump.m4.html
3483 default_viewtext() { # $1=def-file
3484 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
3485 default_storedb "$@"
3486 DT_VIEW="viewtable+$tbl" dumptable html $tbl "name memo file" \
3487 | _m4 -D_TITLE_="$tbl" \
3488 -D_FORM_="`genform $1`" \
3489 -D_DUMPTABLE_="syscmd(cat)" \
3490 $layout/html.m4.html $layout/form+dump.m4.html
3492 default_smail() {
3493 default_storedb "$@"
3494 if [ $? -eq 2 ]; then
3495 _m4 -D_TITLE_="入力" \
3496 -D_FORM_="`genform $1`" \
3497 -D_DUMPTABLE_="" \
3498 $layout/html.m4.html $layout/form+dump.m4.html
3499 return
3500 fi
3501 cond=""
3502 for pk in `gettblpkey $tbl`; do
3503 pv=$(sqlquote $(getpar $pk))
3504 cond="$cond${cond:+ and }$pk=$pv"
3505 done
3506 sql="select rowid from $tbl where $cond;"
3507 rowid=`query "$sql"`
3508 ## err smail1 - "$sql" "-> rowid=$rowid"
3510 while IFS=: read prompt name keytype type args; do # Read from $1
3511 val=`getpar $name`
3512 if [ -n "$val" ]; then
3513 text="$text
3514 $prompt
3515 $name=$val
3516 ---------------------------------------------------------"
3517 fi
3518 case "$type" in
3519 image|document|file)
3520 fn="`getvalbyid $tbl $name $rowid $tmpd`"
3521 fns=$(echo "$fn"|while read fn; do
3522 err mv $tmpd/$fn.orig $tmpd/$fn
3523 mv $tmpd/$fn.orig $tmpd/$fn
3524 rm $tmpd/$fn.rowid # Remove cache flag
3525 ## err "`ls $tmpd/$fn`"
3526 echo $fn
3527 done)
3528 files="$files $fns"
3529 ;;
3530 esac
3531 done < $1
3532 ## err FILES=$files "`ls -lF $tmpd`"
3533 subj="from ${REMOTE_ADDR}"
3534 (echo "$url"
3535 echo "への書き込みがありました。"
3536 echo "------"
3537 echo "$text"
3538 ) | (cd $tmpd &&
3539 err LS="`ls -lF`" &&
3540 $mydir/sendmultipart.sh -t "$admin" -s "$subj" $files)
3541 _m4 -D_TITLE_="入力完了" $layout/html.m4.html
3542 echo "以下の内容で送信しました。" | html p
3543 viewtable $1 $tbl \
3544 `query "select rowid from $tbl order by rowid desc limit 1;"`
3545 echo "戻る" | html a "href=\"?\""