s4

view s4-funcs.sh @ 382:7b1c44bf12e8

Add feature of cloning a group
author HIROSE Yuuji <yuuji@gentei.org>
date Mon, 28 Nov 2016 09:24:20 +0859
parents 165fa0a61d18
children 93ba4a8f3398
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 ### err "select $pk from $1 where rowid=$3" - key=$key '$4(tmp)'=$4
635 for kt in s m; do
636 td=${4:-$tmpd}
637 [ -d $td ] || mkdir -p $td
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 unset primary update
938 gettblconf
939 #err tsc=$tsc, tconfs="$tconfs"
940 conf=`echo "$tconfs"|fgrep "$tsc"=`
941 #err conf=$conf
942 case ${conf#*=} in
943 p*) primary=1 ;;
944 f*) update=1 ;;
945 u*) ;;
946 m*) t=${t}_m;;
947 s*) t=${t}_s;;
948 esac
949 #err t=$t
950 type=text fn=""
951 case $conf in
952 */password)
953 type=encoded ### val=`echo $val|encode`
954 ;;
955 */image*|*/document*)
956 type=`file --mime-type - < "$val" | cut -d' ' -f2`
957 bin="X'`hexize "$val"`'"
958 ;;
959 esac
960 pkey=`echo "$tconfs"|grep "${t0}/.*=p"|sed 1q`
961 pkey=${pkey#/*/} # cut $tbl/
962 pkey=${pkey%=p/*} # cut =p/... -> primary key
963 if [ "$primary" ]; then
964 nulls=`echo "$tconfs"|grep "$t/.*=[fu]/"|sed 's/^.*/, NULL/'|tr -d '\n'`
965 ###sq $db "replace into $t values(\"$val\"$nulls)"
966 query "replace into $t values(\"$val\"$nulls);"
967 elif [ "$update" ]; then
968 ###sq $db "update $1 set $c=\"$val\" where $pkey=\"$p\""
969 query "update $1 set $c=\"$val\" where $pkey=\"$p\";"
970 else
971 #err "replace into $t values(\"$p\", \"$c\", \"$type\", \"$val\", \"$bin\")"
972 ###sq $db "replace into $t values(\"$p\", \"$c\", \"$type\", \"$val\", \"$bin\")"
973 query "replace into $t values(\"$p\", \"$c\", \"$type\", \"$val\", \"$bin\");"
974 fi
975 )
976 }
977 expire() (
978 at="${1:-$timeout}"
979 FMT="${2:-%F %T}"
980 TZ=GMT gdate -d "$at" +"$FMT"
981 )
982 addsession() {
983 # expireをセット
984 # loginの先にどの画面に行くかの状態遷移表書式を決める
985 expire=`expire ${2:-"+1min"}`
986 query "replace into session values('$1', '$expire');"
987 # Remove old session parameters
988 now=`expire now`
989 query "delete from session where expire < '$now';"
990 }
991 gencookie() (
992 for kv; do
993 expire="`expire '' '%a, %d-%b-%Y %H:%M:%S GMT'`"
994 echo "Set-Cookie: $kv; expires=$expire"
995 done
996 )
997 contenttype() {
998 echo "Content-type: ${1:-text/html; charset=utf-8}"
999 contenttype() {} # Only need to work once
1001 putheader() {
1004 putfooter() {
1005 _m4 -D_TITLE_="${TITLE:-$myname}" $layout/footer.m4.html
1007 getcookie() (
1008 for kv in `echo $HTTP_COOKIE|sed 's/[;, ]/ /g'`; do
1009 k="${kv%%=*}"
1010 v="`echo ${kv#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
1011 query "replace into cookie values('$session', '$k', 'string', \"$v\");"
1012 done
1014 genrandom() {
1015 # $1=columns (default: 10)
1016 dd if=/dev/urandom count=1 2>/dev/null|nkf -MB|fold -w${1:-10}|sed -n 10p
1018 genserial() {
1019 echo $((($(date +%s)-1433084400)/10))c$$
1021 smail() {
1022 # smail rcpts subj (file)
1023 # $SMAIL_TO <- Recipient value of To: header
1024 # $MAIL_FROM <- From: header value
1025 from=`echo "${MAIL_FROM:-$admin}"|nkf -jM|tr -d '\n'`
1026 rcpt=`echo $1` # strip newlines
1027 subj=`echo $2|nkf -jM|tr -d '\n'`
1028 (_m4 -D_RCPT_="${SMAIL_TO:-$rcpt}" -D_SUBJ_="\`$subj'" -D_FROM_="$from" $msgdir/mail-header.m4
1029 cat $3 | nkf -jd ) | sendmail -f $admin $rcpt
1031 setviastring() {
1032 table=$1
1033 oifs="$IFS"
1034 IFS="&"
1035 for us in $2; do
1036 k=${us%%=*}
1037 v="`echo ${us#*=}|tr '%+' '= '|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
1038 query "replace into $table values('$session', '$k', 'string', \"$v\");"
1039 #echo $k=$v
1040 done
1041 IFS="$oifs"
1043 checkdomain() (
1044 # Check the validity of domain by referring DNS
1045 item=$1
1046 err checkdomain $1
1047 host ${item#*@} 1>&3 2>&3
1048 host ${item#*@} >/dev/null 2>&1
1050 pwcheck() {
1051 # $1=passwd
1052 dbpswd=`getpwfield $user pswd`
1053 encpswd=`mycrypt "$1" "$dbpswd"`
1054 ## err user=$user, pswd=$1, db=$dbpswd, enc=$encpswd
1055 [ x"$dbpswd" = x"$encpswd" ]
1057 mypwhash() {
1058 mycrypt `cat` `genrandom 5`
1060 wasureta() {
1061 user=$1
1062 if ! checkdomain $user; then
1063 contenttype; echo
1064 _m4 -D_TITLE_='Invalid email' $layout/title-only.html
1065 echo "ユーザ名($user)には正しいメイルアドレスが必要です。" | html p
1066 putfooter
1067 exit 0
1068 fi
1069 newpswd=`genrandom` # newsalt=`genrandom 5`
1070 #encpswd=`mycrypt "$newpswd" "$newsalt"`
1071 encpswd=`echo $newpswd|mypwhash`
1072 dbsetbyid user $user pswd "$encpswd"
1073 # Avoid $user substitution with m4, because $url comes from user input.
1074 _m4 -D_PSWD_="$newpswd" -D_URL_="$url" -D_ADMIN_="$admin" \
1075 $msgdir/mail-newaccount.m4 \
1076 | sed "s/_USER_/$user/g" \
1077 | smail $user "New Account"
1079 checkauth() {
1080 user=`getpar user`
1081 skc=`getpar skey` # from cookie
1082 [ -z "$user" ] && return 3
1083 skey="`getpwfield $user skey`"
1084 if [ -n "$skey" ]; then
1085 if [ x"$skey" = x"$skc" ]; then
1086 return 0
1087 fi
1088 fi
1089 pswd=`getpar pswd`
1090 quser=`sqlquotestr "$user"`
1091 dbuser=`query "SELECT name FROM user WHERE name=$quser;"`
1092 if [ -z "$dbuser" ]; then
1093 return 1
1094 elif [ x"$pswd" = x"wasureta" ]; then
1095 wasureta $user
1096 return 1 # wasureta error
1097 fi
1098 # dbpswd="`sq $db \"select pswd from passwd where name='$user'\"`"
1099 # putheader; echo; echo user=$user, db=$dbpswd, enc=$encpswd
1100 if pwcheck "$pswd"; then
1101 newsession=`genrandom 50`
1102 dbsetbyid user $user skey "$newsession"
1103 gencookie "user=$user" "skey=$newsession"
1104 return 0
1105 fi
1106 return 2 # Password mismatch
1108 showlogin() {
1109 args=`echo $myargs|tr ' ' '+'`
1110 _m4 -D_SYSNAME_="Welcome" -D_MYNAME_="$myname${args+?}$args" \
1111 $layout/login.m4.html
1112 exit 0
1114 dologin() {
1115 checkauth
1116 st=$?
1117 if [ $st != 0 ]; then
1118 contenttype; echo
1119 _m4 -D_USER_="$user" -D_URL_="$url" -D_ADMIN_="$admin" \
1120 $msgdir/login-fail-$st.m4.html
1121 showlogin # and EXIT
1122 fi
1125 # Do instant jobs here
1126 dbsetup
1127 trap cleanup INT HUP EXIT TERM PIPE
1128 # trap cleanup INT HUP
1130 err() {
1131 echo "$@" 1>&3
1134 cgiinit() {
1135 session=`date +%F-$$`
1136 tmpf=tmp/stream
1137 tmpd=`tmpd=$tmpdir mktempd`
1138 tmpfiles=$tmpfiles" $tmpd"
1139 addsession $session
1140 getcookie
1141 case "$REQUEST_METHOD" in
1142 get|GET) s="$QUERY_STRING" ;;
1143 post|POST) ## dd count=$CONTENT_LENGTH bs=1 of=$tmpf 2>/dev/null #slow
1144 ## dd bs=$CONTENT_LENGTH count=1 of=$tmpf # NOT working
1145 # cat > $tmpf # too much?
1146 head -c $CONTENT_LENGTH > $tmpf # safe?
1147 (echo CL=$CONTENT_LENGTH; ls -lF $tmpf) 1>&3
1148 s="`cat tmp/stream`"
1149 tmpfiles=$tmpfiles"${tmpfiles+ }$tmpf"
1150 ;;
1151 esac
1152 case "$CONTENT_TYPE" in
1153 *boundary*)
1154 bndry=${CONTENT_TYPE#*boundary=}
1155 #for us in `LC_CTYPE=C ./mpsplit.rb "$bndry" $tmpd < $tmpf`
1156 for us in `LC_CTYPE=C ./mpsplit.pl "$bndry" $tmpd < $tmpf`
1157 do
1158 k=${us%%\=*}
1159 #echo u=$us
1160 #v="`echo ${us#*=}|nkf -Ww -mQ|sed -e 's/\"/\"\"/g'`"
1161 v="`echo ${us#*=}|unhexize|sed -e 's/\"/\"\"/g'`"
1162 # err k=$k v=$v
1163 case "$k" in
1164 *:filename)
1165 type='file'; k=${k%:filename}
1166 # DO NOT ALLOW Space and '|' in file names
1167 newv=`echo "$v"|sed 's/[ \|]/X/g'`
1168 if [ x"$v" != x"$newv" ]; then
1170 fi
1171 # (echo k=$k v="[$v]"; ls -lF "$tmpd/$v"; file --mime-type "$tmpd/$v") 1>&3
1172 case `file --mime-type - < "$tmpd/$v"|cut -d' ' -f2` in
1173 [Ii]mage/x-xcf)
1174 bzip2 "$tmpd/$v"
1175 v=${v}.bz2
1176 ;;
1177 [Ii]mage/x-*|*/vnd.*) ;;
1178 [Ii]mage/*)
1179 mogrify -resize $maximagexy'>' "$tmpd/$v"
1180 ;;
1181 esac
1182 ;;
1183 *)
1184 type='string'
1185 ;;
1186 esac
1187 #sq $db "replace into par values('$session', '$k', '$type', \"$v\")"
1188 setpar "$k" "$type" "$v"
1189 done
1190 ;;
1191 *)
1192 setviastring par "$s"
1193 ;;
1194 esac
1196 email4group() {
1197 # Get for-$1=group email address(es) for $2...=users
1198 qgrp=`sqlquote "$1"`; shift
1199 users=`for i; do sqlquote "$i"; done`
1200 users=`echo $users|tr ' ' ','`
1201 sql="select coalesce(s.val, g.user) from grp_mem g
1202 left join grp_mem_s s on g.gname=s.gname and g.user=s.user
1203 and s.key='email'
1204 where g.gname=$qgrp and g.user in ($users);"
1205 query "$sql"
1207 email4groupbyuid() {
1208 # Get for-$1=group email address(es) for $2...=user-ids
1209 qgrp=`sqlquote "$1"`; shift
1210 uids=`echo "$@"`
1211 uids=`echo $uids|tr ' ' ','`
1212 sql="WITH
1213 grpemails AS (
1214 SELECT gname, user, val email
1215 FROM grp_mem NATURAL JOIN grp_mem_s
1216 WHERE key='email' AND gname=$qgrp),
1217 useremails AS (
1218 SELECT user.rowid rid, user.name, val email
1219 FROM user
1220 LEFT JOIN user_s
1221 ON user.name=user_s.name AND user_s.key='email')
1222 SELECT DISTINCT coalesce(g.email, u.name)
1223 FROM useremails u LEFT JOIN grpemails g
1224 ON u.name=g.user
1225 WHERE u.rid in ($uids);"
1226 ## err email4gByid `echo $sql`
1227 query "$sql"
1229 collectemail() (
1230 # Collect email addresses for group $1
1231 # If $TEAM is set, filter by team name
1232 # If $EXCEPT is set as username(s) delimited by comma,
1233 # remove $EXCEPT from list: ....NOT IN ($EXCEPT)
1234 for e; do
1235 if isuser "$e"; then
1236 em=`query "select val from user_m where name='$e' and key='email';"`
1237 [ -n "$em" ] && echo "$em" || echo "$e"
1238 else
1239 qgrp=`sqlquote "$e"`
1240 if [ -z "$TEAM" ]; then
1241 gmem="grp_mem"
1242 else
1243 tm=`sqlquote "$TEAM"`
1244 gmem="(SELECT gname, user FROM grp_mem_m WHERE gname='$e' AND key='team' AND val=$tm)"
1245 fi
1246 ex=${EXCEPT:+"AND g.user NOT IN ($EXCEPT)"}
1247 sql="select coalesce(s.val,um.val,g.user) from
1248 $gmem g left join grp_mem_s s
1249 on g.gname=s.gname and g.user=s.user and s.key='email'
1250 left join user_m um on g.user=um.name and um.key='email'
1251 where g.gname=$qgrp $ex;"
1252 ## err CollectEmail: `echo "$sql"`
1253 query "$sql"
1254 fi
1255 done
1257 sendinvitation() (
1258 # $1=email
1259 iss="invite-`date +%s`-$user"
1260 addsession $iss +${memoplimitdays}days # 1 week due date
1261 query "replace into par values('$iss', 'invite', 'string', \"$1\");"
1262 gecos=`gecos`
1263 name=$user"${gecos:+($gecos)}"
1264 regist="$urlbase?reg+$iss"
1265 _m4 -D_URL_="$urlbase" \
1266 -D_USER_="$name" \
1267 -D_EMAIL_="$1" \
1268 -D_REGIST_="$regist" \
1269 -D_ADMIN_="$admin" \
1270 $msgdir/mail-invite.m4 \
1271 | smail $1 "BBSへの御招待"
1272 return 0
1274 emaildomaincheck() {
1275 case "$1" in
1276 *@*@*) echo "無効なアドレスです"; return 1 ;;
1277 *@*)
1278 local=${1%@*} domain=${1#*@}
1279 if ! host $domain >/dev/null 2>&1; then
1280 echo "ドメイン($domain)が見付かりません。"
1281 return 2
1282 fi
1283 return 0
1284 ;;
1285 *) echo "正しいメイルアドレスをいれてください"; return 3 ;;
1286 esac
1288 invite() {
1289 email=`getpar email`
1290 case $email in
1291 *@*@*) repo="無効なアドレスです" ;;
1292 *@*)
1293 local=${email%@*} domain=${email#*@}
1294 if ! repo=`emaildomaincheck $email`; then
1295 repo="招待アドレスのエラー: $repo"
1296 elif [ -n "`query \"select * from user where name='$email';\"`" ]; then
1297 repo="$email さんは既に加入しています。"
1298 elif sendinvitation $email; then
1299 repo="アドレス($email)宛に案内を送信しました。"
1300 fi ;;
1301 "") repo="招待したい人のメイルアドレスを入力してください。" ;;
1302 *) repo="無効なアドレスです" ;;
1303 esac
1304 addr=`query "select val from par where sessid like 'invite-%-$user';"`
1305 if [ -n "$addr" ]; then
1306 susp="<h2>招待済みで加入待ちのアドレス</h2><pre>$addr</pre>"
1307 fi
1308 _m4 -D_TITLE_="招待" -D_REPORT_="\`$repo'" -D_ACTION_="?invite" \
1309 -D_BODYCLASS_="default" -D_SUSPENDED_="$susp" \
1310 $layout/html.m4.html $layout/invite.m4.html
1312 regist() {
1313 # $1=session-id-for-invitation
1314 _m4 -D_TITLE_="Invitation" $layout/html.m4.html
1315 if [ -z "$1" ]; then
1316 echo "bye bye" | html p
1317 reutrn
1318 fi
1319 email=`session=$1 getpar invite`
1320 if [ -z "$email" ];then
1321 cat<<EOF
1322 <p>無効な招待状チケットです。</p>
1323 <p>招待状の有効期限(1週間)が切れているか、チケット番号が異なっています。
1324 加入している人に、再度招待してもらいましょう。</p>
1325 EOF
1326 return
1327 fi
1328 echo "$email さんようこそ" | html h2
1329 query "replace into user values('$email');"
1330 # Fake login password to wasureta
1331 query "replace into par values('$session', 'pswd', 'string', 'wasureta'),
1332 ('$session', 'user', 'string', '$email');"
1333 wasureta $email
1334 echo "このアドレスに初期パスワードを送信しました。" |html p
1335 echo "新着メイルを確認してログインしてください。" |html p
1336 addsession $1 # for removal after 1 minute
1337 _m4 -D_SYSNAME_="Initial Login" -D_MYNAME_="$myname?userconf" \
1338 $layout/login.m4.html
1339 return
1341 group_safename() {
1342 # Convert $1 to safe group name
1343 echo "$1" | tr -d '"'"'",
1345 groupupdate() {
1346 gname=`getpar gname`
1347 qgname=`sqlquote $gname`
1348 if [ -n "$gname" ]; then
1349 # See ALSO same job in showgroup()
1350 newgname=`group_safename "$gname"`
1351 err newgname=$newgname
1352 if [ x"$newgname" != x"$gname" ]; then
1353 err NewGNAME: gname=$newgname
1354 gname=$newgname
1355 echo "使用禁止文字を除去し $gname としました。" | html p
1356 replpar gname string "$gname"
1357 fi
1358 # Name confliction check
1359 parow=`getpar rowid`
1360 ## err parow=$parow
1361 qgname=`sqlquote $gname` # Set again in case gname modified
1362 query "BEGIN EXCLUSIVE;"
1363 ## err "select count(gname) from grp where rowid != ${parow:-0} and gname = $qgname;"
1364 count=$(query "select count(gname) from grp where rowid != ${parow:-0} and gname = $qgname;")
1365 if [ $count -gt 0 ]; then
1366 echo "そのグループ名は既にあります。" | html p
1367 query "END;"
1368 return
1369 fi
1370 par2table $formdir/grp.def
1371 query "END TRANSACTION;"
1372 # Remove orphan
1373 : <<EOF
1374 select a.id,b.val from (select * from blog where id in
1375 (select id from blog_s where key='owner'
1376 and val not in (select name from user union select gname from grp)))
1377 a left join blog_s b on a.id=b.id and b.key='owner';
1378 EOF
1379 rm=`getpar rm` cfm=`getpar confirm`
1380 ## err groupupdate:::: after par2tbl rmcfm=$rm$cfm
1381 if [ x"$rm$cfm" = x"yesyes" ]; then
1382 if [ -z "`query \"select gname from grp where gname=$qgname;\"`" ]; then
1383 sql="delete from blog where id in
1384 (select id from blog_s where key='owner' and val=$qgname);"
1385 err rm-grp cleaning sql=`echo $sql`
1386 query "$sql";
1387 grps # When removing a group, switch to grp-list
1388 return # and return
1389 fi
1390 fi
1391 [ -z "$parow" ] && joingrp "$gname" "$user" yes "" as-admin
1392 fi
1393 sql="select rowid from grp where gname=$qgname;"
1394 grid=$(query $sql)
1395 ## err grpupdate:new-grid=$grid, sql=$sql
1396 grp $grid
1398 groupclone() {
1399 # $1=grp-rowid of clone-base group
1400 qgrp=`query "SELECT quote(gname) FROM grp WHERE rowid=$1;"`
1401 if [ -z "$qgrp" ]; then
1402 echo "無効なグループIDです($1)" | html p
1403 return
1404 fi
1405 i=0
1406 while true; do
1407 copy="-copy$i"
1408 newqname=`query "SELECT quote($qgrp || '$copy');"`
1409 # err Trying new grp=$newqname with copy=$copy
1410 test=`query "SELECT gname FROM grp WHERE gname=$newqname;"`
1411 if [ -n "$test" ]; then
1412 i=$((i++))
1413 continue
1414 fi
1415 break
1416 done
1417 # Creating New group "$newqname" with members of old group
1418 # err Creating new grp=$newqname with copy=$copy
1419 query<<-EOF
1420 BEGIN;
1421 INSERT INTO grp VALUES($newqname); -- Create NEW one
1422 REPLACE INTO grp_s(gname, key, val) -- Copy tag
1423 SELECT $newqname, key, val
1424 FROM grp_s WHERE gname=$qgrp AND key IN ('tag', 'mode');
1425 REPLACE INTO grp_s(gname, key, type, val) -- Copy gecos with "copy$n"
1426 SELECT $newqname, key, type, val || '$copy'
1427 FROM grp_s WHERE gname=$qgrp AND key='gecos';
1428 -- Copy members and their configuration --
1429 REPLACE INTO grp_mem SELECT $newqname, user
1430 FROM grp_mem WHERE gname=$qgrp;
1431 REPLACE INTO grp_mem_s SELECT $newqname, user, key, type, val, bin
1432 FROM grp_mem_s WHERE gname=$qgrp;
1433 REPLACE INTO grp_mem_m SELECT $newqname, user, key, type, val, bin
1434 FROM grp_mem_m WHERE gname=$qgrp;
1435 -- Copy administrators --
1436 REPLACE INTO grp_adm SELECT $newqname, user
1437 FROM grp_mem WHERE gname=$qgrp;
1438 COMMIT;
1439 EOF
1440 newrowid=`query "SELECT rowid FROM grp WHERE gname=$newqname;"`
1441 STOPCLONEMSG=1 groupconf "$newrowid"
1443 groupman() {
1444 note="<p>グループ名に使用できない文字は自動的に削除されます。</p>"
1446 GF_STAGE="grpconf"
1447 GF_STAGE=groupupdate
1448 DT_VIEW=grp dumptable html grp 'gname gecos:DESC mtime:TIME' 'order by b.TIME desc' \
1449 |_m4 -D_TITLE_="グループ作成" \
1450 -D_FORM_="$note`genform $formdir/grp.def`" \
1451 -D_DUMPTABLE_="syscmd(cat)" \
1452 $layout/html.m4.html $layout/form+dump.m4.html
1454 userconf() {
1455 [ -n "`getpar rowid`" ] && par2table $formdir/user.def
1456 _m4 -D_BODYCLASS_=userconf -D_TITLE_="ユーザ情報編集" $layout/html.m4.html
1457 GF_ACTION="?home" edittable "$formdir/user.def" "user" "$user"
1459 groupconf() {
1460 # $1=rowid in grp (2015-07-21 changed from gname)
1461 [ -n "`getpar rowid`" ] && par2table $formdir/grp.def
1462 _m4 -D_BODYCLASS_=groupconf -D_TITLE_="グループ情報編集" $layout/html.m4.html
1463 #rowid=`query "select rowid from grp where gname='$1';"`
1464 rowid=${1%%[!A-Z0-9a-z_]*}
1465 # GF_ACTION="?grp+$1" edittable "$formdir/grp.def" "grp" "$rowid" #2015-0804
1466 GF_STAGE="groupupdate" edittable "$formdir/grp.def" "grp" "$rowid"
1467 test -z "$STOPCLONEMSG" &&
1468 echo "<a href=\"?groupclone+$rowid\">同じ構成員で新規グループ作成</a>" \
1469 | html p
1471 mems() {
1472 _m4 -D_TITLE_="参加者一覧" -D_BODYCLASS_=listmember $layout/html.m4.html
1473 kwd=`getpar kwd`
1474 listmember $kwd
1476 grps() {
1477 _m4 -D_TITLE_="グループ一覧" -D_BODYCLASS_=listgroup $layout/html.m4.html
1478 kwd=`getpar kwd`
1479 listgroup $kwd \
1480 | _m4 -D_DUMPTABLE_="syscmd(cat)" \
1481 -D_TITLE_="グループ関連操作" \
1482 -D_FORM_="<a href=\"?groupman\">新規グループ作成</a>" \
1483 $layout/form+dump.m4.html
1485 grp() { # $1=group-rowid
1486 gpg=`getpar grp`
1487 grid=${1:-$gpg}
1488 grp=`getgroupbyid "$grid"`
1489 ## . ./s4-blog.sh
1490 jg=`getpar joingrp`
1491 if [ -n "$jg" ]; then
1492 [ -n "$jg" -a -n "$grp" ] &&
1493 joingrp "$grp" "$user" "$jg" "`getpar email`"
1494 fi
1495 htmlheader=$layout/html.m4.html
1496 showgroup "$grid"
1498 sql4interestblogs() {
1499 cat<<EOF
1500 CREATE TEMPORARY VIEW interestblogs AS
1501 SELECT blog.rowid rid, id, author
1502 FROM blog
1503 NATURAL JOIN
1504 (SELECT id, val owner FROM blog_s WHERE key='owner') bs
1505 WHERE CASE WHEN (SELECT name FROM user where name=bs.owner) IS NOT NULL
1506 THEN 1 -- blog owner is an user, READABLE
1507 WHEN (SELECT user FROM grp_mem
1508 WHERE gname=bs.owner AND user='$user') IS NULL
1509 THEN 0
1510 ELSE 1
1511 END;
1512 EOF
1514 listnewblogsql() { # $1=user
1515 deftime=`query "SELECT coalesce((SELECT time FROM acclog
1516 WHERE user='$user'
1517 AND tblrowid=$blogreadflagrowid),
1518 "0");"`
1519 cat<<EOF # | tee tmp/sql.out
1520 `sql4interestblogs`
1521 WITH article_ctime as (
1522 SELECT id,blogid,author,val ctime
1523 FROM article join article_s s using(id)
1524 WHERE s.key='ctime'
1525 ), blog_title_owner as (
1526 SELECT blg.rid brid, id,
1527 max(case key when 'title' then val end) title,
1528 max(case key when 'owner' then val end) owner
1529 FROM interestblogs blg, blog_s using(id) group by id
1530 ), visited AS (
1531 SELECT b.id id, brid, b.owner owner, b.title title, ctime, ac.author author
1532 FROM blog_title_owner b, article_ctime ac
1533 JOIN acclog al
1534 ON b.id=ac.blogid
1535 AND al.tbl='blog'
1536 AND al.tblrowid=brid
1537 AND al.user='$user'
1538 AND al.time < ctime
1539 AND '$deftime' < ctime
1540 ), unvisited as (
1541 SELECT b.id id, brid, b.owner owner, b.title title, ctime, ac.author author
1542 FROM blog_title_owner b, article_ctime ac
1543 ON b.id=ac.blogid
1544 WHERE brid NOT IN (SELECT tblrowid FROM acclog
1545 WHERE tbl='blog' AND user='$user')
1546 AND ctime > '$deftime'
1547 ), blogall as (
1548 /* ---------------------------------------
1549 Collect new articles with dividing them into visited and unvisited
1550 separately, because constructing joined table of artice X acclog
1551 tends to become HUGE combinations.
1552 --------------------------------------- */
1553 SELECT * FROM visited UNION SELECT * FROM unvisited
1554 ), news as (
1555 select bl.brid brid, bl.title, bl.id blid, ctime,
1556 count(bl.id) "新着", bl.owner, bl.author
1557 from blogall bl /* left join a_u l
1558 on bl.brid=l.tblrowid */
1559 group by bl.id order by ctime desc,"新着" desc, bl.id
1560 LIMIT 10
1561 ) SELECT brid LINK, "新着",
1562 (SELECT count(*) FROM article WHERE blogid=blid) "総数",
1563 ctime, title,
1564 (SELECT gecos FROM gecoses WHERE name=author) gecos
1565 FROM news;
1566 EOF
1569 search_form() {
1570 help="(1)空白区切りの単語で本文検索
1571 (2)@YYYY-MM-DD 日付け(シェルパターン可)で日付け検索
1572 @2016-0[1-6] → 2016年1月から6月
1573 @>2016-01 @<2016-02-15 → 2016年1月から2月14日までの期間
1574 @week → 最近一週間
1575 (3)#番号 で記事ID検索
1576 (1)と(2)は組み合わせOK
1577 例: @2016-10-0[1-9] 芋煮
1578 → 2016年10月上旬でキーワード「芋煮」を含む記事検索"
1579 auth=""
1580 placeholder="全記事からの検索"
1581 case "$1" in
1582 author=*)
1583 a=`echo "${1#author=}"|htmlescape`
1584 g=`gecos ${1#author=}`
1585 auth="<input type=\"hidden\" name=\"author\" value=\"$a\">"
1586 placeholder="このユーザの書込検索"
1587 help="★★ $g さんの書き込みから検索します$nl$help"
1588 ;;
1589 esac
1590 cat<<-EOF
1591 <div class="fr">
1592 <form action="$myname">$auth
1593 <input type="text" name="kwd" value="" title="$help"
1594 placeholder=" $placeholder " width="10" accesskey="k">
1595 ${touchpanel:+<p class="help">$help</p>}
1596 <input type="hidden" name="stage" value="searchart">
1597 </form>
1598 </div>
1599 EOF
1602 imgsrc_cache() (
1603 # $1 = directory for cache'ing
1604 # $2 = table (user_m or grp_m)
1605 # $3 = keycond (was: condition for choosingowner)
1606 # $4 = size : S = Small, M = Medium, O = Original
1607 dir="$1" tbl="$2"
1608 keycond="$3"
1609 whos="$keycond AND key='profimg' AND type LIKE 'file:image%'
1610 ORDER BY rowid DESC LIMIT 1"
1611 [ -d "$dir" ] || mkdir -p "$dir"
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 tmpf=$tmpd/imgsrc_cache.$$
1636 sum=`query "$sql1" | tee $tmpf | encode` # encode() is maybe sha1
1637 if test -s "$sumfile" && [ x"`cat $sumfile`" = x"$sum" ]; then
1638 # if cache is fresh,
1639 echo "<img src=\"$cacheimg\">"
1640 else
1641 fifo=$tmpd/fifo; mkfifo $fifo
1642 fmt=${filename##*.}
1643 ## [[ NOTE ]]
1644 ## a. convert oldimage newimage
1645 ## b. convert oldimage fmt:- | convert - newimage
1646 ## b is much smaller than a
1647 cat $tmpf | unhexize \
1648 | tee $fifo \
1649 | convert -define ${fmt}:size=${iconxy_M}x${iconxy_M} \
1650 -resize ${iconxy_M}x${iconxy_M}'>' - ${fmt}:- \
1651 | convert - "$cacheimg_M" &
1652 cat $fifo | convert -define ${fmt}:size=${iconxy_S}x${iconxy_S} \
1653 -resize ${iconxy_S}x${iconxy_S}'>' - ${fmt}:- \
1654 | convert - "$cacheimg_S" &
1655 printf '%s' "<img src=\"data:${filetype},"
1656 cat $tmpf | sed 's/\(..\)/%\1/g'
1657 echo '">'
1658 echo "$sum" > $sumfile
1659 fi
1660 ## Now preparing cache image, done.
1661 ## Store this information to DB
1662 stbl=${tbl%_m}_s # user_s or grp_s
1663 pkey=${keycond%%=*} # Primary Key name
1664 pval=${keycond#*=} # Primary Key value
1665 query <<-EOF
1666 REPLACE INTO $stbl($pkey, key, type, val)
1667 VALUES($pval, '$iconcachekey', 'string', `sqlquote "$cacheimg_S"`);
1668 EOF
1671 showhome() {
1672 # $1=userRowIdToShow
1673 err showhome \$1=$1
1674 case "$1" in
1675 *@*) uname=`getvalbypkey user name "$1"` ;;
1676 *) uname=`getvalbyid user name $1` ;;
1677 esac
1678 ## err ShowHome: uname=$uname
1679 td=`getcachedir home/"$1"`
1680 gecos=`gecos "$uname"`
1681 ## err SH:gecos=$gecos
1682 GF_VIEWONLY=1
1683 cond="gname in (select gname from grp_mem where user='$uname')"
1684 search_form_args=""
1685 if [ x"$user" = x"$uname" ]; then
1686 conflink="<a href=\"?userconf\" accesskey=\"e\"
1687 title=\"E\">プロフィールの編集</a> /
1688 <a href=\"?blog\" accesskey=\"n\" title=\"N\">新規話題の作成</a>"
1689 # Display folders
1690 sql="select count(id) from article_m where id
1691 in (select id from article where author='$user')
1692 and type like 'file:%';"
1693 ## err nfile-sql=`echo "$sql"`
1694 nfile=`query "$sql"`
1695 # err nfile=$nfile
1696 if [ $nfile -gt 0 ]; then
1697 conflink="$conflink / <a href=\"?lsmyfile\" accesskey=\"l\"
1698 title=\"L\">過去の提出ファイル</a>"
1699 fi
1700 else
1701 search_form_args="author=$uname"
1702 fi
1703 . ./s4-blog.sh
1705 tf=$tmpd/title.$$ pf=$tmpd/profile.$$ bf=$tmpd/blogs.$$ sf=$tmpd/search.$$
1706 search_form $search_form_args > $sf
1707 echo "$gecos さん" > $tf
1708 { echo "<div class=\"noprofimg\">"
1709 viewtable $formdir/user.def user $1
1710 echo "</div>"
1711 } > $pf
1713 sqcond="WHERE name='$uname' AND key='profimg' AND type LIKE 'file:image%'"
1714 img=`query "SELECT type FROM user_m $sqcond LIMIT 1;"`
1715 imf=$tmpd/profimg.$$; touch $imf
1716 if [ -n "$img" ]; then
1717 if true; then
1718 tbl=user_m
1719 enticond="name='$uname'"
1720 imgsrc_cache "$td/main" user_m "$enticond" M
1721 else
1722 { printf '%s' "<IMG src=\"data:${img#file:},"
1723 query "SELECT hex(bin) FROM user_m $sqcond ORDER BY rowid LIMIT 1;" \
1724 | sed 's/\(..\)/%\1/g'
1725 echo '">'
1727 fi > $imf
1728 fi
1729 nblog=`query "SELECT count(id) FROM blog_s WHERE key='owner' AND \
1730 val='$uname';"`
1731 listblog $uname > $bf
1733 hometail=$tmpd/tail.$$
1734 mkfifo $hometail
1736 #Calling listgroupbytable, originally here
1739 # Display Most Recent Entry
1740 shortval=${dumpcollen:+"substr(val, 0, $dumpcollen)"}
1741 shortval=${shortval:-val}
1743 # The m.aid in the next line is suspicious. But works fine in SQLite3...
1744 DT_SQL="SELECT b.rowid || '#' || m.aid LINK,
1745 ctime,
1746 (SELECT $shortval FROM blog_s WHERE key='title' AND id=b.id) title,
1747 (SELECT gecos FROM gecoses
1748 WHERE name=(SELECT val FROM blog_s
1749 WHERE key='owner' AND id=b.id)) owner,
1750 (SELECT $shortval val FROM article_s WHERE id=m.aid AND key='text') text
1751 FROM blog b
1752 JOIN
1753 (SELECT distinct blogid, a.id aid, max(val) ctime
1754 FROM article a, article_s s
1755 ON a.id=s.id AND a.author='$uname' AND s.key='ctime'
1756 GROUP BY blogid ORDER BY val DESC LIMIT 50
1757 ) m
1758 ON b.id=m.blogid;"
1759 # This should be as follows
1760 : <<EOF
1761 WITH arts AS(
1762 SELECT (SELECT rowid FROM blog WHERE id=a.blogid) brid,
1763 a.blogid, a.id id, s.val ctime
1764 FROM article a NATURAL JOIN article_s s
1765 WHERE s.key = 'ctime' AND a.author='$user'
1766 GROUP by s.id
1768 SELECT a0.brid,a0.blogid,a0.id,a0.ctime
1769 FROM arts a0
1770 JOIN
1771 (SELECT blogid,max(ctime) mct FROM arts a1 GROUP BY blogid) a1
1772 ON a0.blogid=a1.blogid AND a0.ctime=a1.mct
1773 ORDER BY ctime DESC LIMIT 50;
1774 EOF
1776 cat<<-EOF
1777 `cgi_radio foldtabs yes 'id="mre" accesskey="d"'`<label
1778 for="mre" title="D">最近の書き込み先</label>
1779 <div class="lcto">
1780 `DT_VIEW=replyblog dumptable html blog`
1781 </div>
1782 EOF
1783 unset DT_SQL
1784 if [ x"$user" = x"$uname" ]; then
1785 # Display NEWS
1786 # 2016-06-26
1787 if [ x"`getpar readchk``getpar read`" = x"yesyes" ]; then
1788 acclog blog $blogreadflagrowid
1789 # echo "全部既読にしました" | html p
1790 fi
1791 # 2016-02-19 Counting NEWS without using dumptable.
1792 sql=`listnewblogsql "$user"`
1793 new10=`DT_SQL="$sql" DT_VIEW=replyblog dumptable html blog`
1794 cont=`echo "$new10"|grep "^<TR>"|wc -l`
1795 cont=$((cont-1))
1796 err newcount=$cont
1797 if [ $cont -gt 0 ]; then
1798 #echo "全体の新着記事${cont}傑" | html h2
1799 cgi_radio foldtabs yes 'id="new10" accesskey="f"'
1800 echo "<label for=\"new10\" title=\"X\">新着${cont}傑</label><div>"
1801 cat<<-EOF | html form 'action="?home"'
1802 `cgi_checkbox readchk yes 'id="read"'`<label
1803 for="read">新着ふくめて全部読んだことにする</label>
1804 `cgi_submit '確定'`
1805 `cgi_hidden read yes`
1806 EOF
1807 echo "$new10 <!-- new10 -->"
1808 echo "</div>"
1809 fi
1810 else # Not My Home ($user != $uname)
1811 : # DT_SQL=
1812 fi
1813 ) > $hometail & # Is background call safe to m4??
1815 listgroupbytable $formdir/grp.def $cond |
1816 _m4 -D_BODYCLASS_=home -D_TITLE_="spaste(\`$tf')" \
1817 -D_PROFILE_="spaste(\`$pf')$conflink" \
1818 -D_PROFIMG_="spaste(\`$imf')" \
1819 -D_BLOGS_="spaste(\`$bf')" \
1820 -D_SEARCH_="spaste(\`$sf')" \
1821 -D_NBLOG_="$nblog" \
1822 -D_GROUPS_="syscmd(\`cat')" \
1823 -D_HOMETAIL_="syscmd(\`cat $hometail')" \
1824 $layout/html.m4.html $layout/home.m4.html
1826 # Record access log
1827 [ -n "$1" ] && [ x"$1" != x"$user" ] && acclog user $1
1829 commission() { # $1=grp-rowid $2=user-rowid
1830 contenttype; echo
1831 ## err commission: "$@"
1832 gname=`getgroupbyid $1`
1833 echo "グループ $gname 管理者委任" \
1834 | _m4 -D_TITLE_="syscmd(\`cat')" $layout/html.m4.html
1835 if [ -n "$2" ]; then
1836 grp_reg_adm "$@"
1837 else
1838 echo "無効な指定です。普通のアクセスならここに来ないはず。"|html p
1839 fi
1841 listgroupbytable() {
1842 # $1=deffile $2...=condition
1843 tagline=`grep :tag: $1`; shift
1844 and="${1:+and }" where=${1:+where }
1845 href="<a href=\"$myname?grp+"
1846 echo '<div class="listgroup">'
1847 NGsql="select distinct tag from\
1848 (select gname, max(case key when 'tag' then val end) as tag, \
1849 max(case key when 'ctime' then val end) as ctime\
1850 from grp_s group by gname order by ctime);"
1851 sql="select val from grp_s where key='tag' $and$* group by val;"
1852 ## err ListGRP: query sql="$sql"
1853 for tag in `query "$sql"`
1854 do
1855 ## err ListGrp: tag=$tag
1856 tn=${tagline%%=${tag}*}
1857 tn=${tn##*[ :]}
1858 sql="select rowid||':'||gname as 'グループ名',説明 from
1859 (select (select rowid from grp g where g.gname=grp_s.gname)
1860 as rowid,
1861 gname,
1862 max(case key when 'gecos' then val end) as '説明',
1863 max(case key when 'tag' then val end) as 'tag',
1864 max(case key when 'mtime' then val end) as mtime from grp_s
1865 $where$* group by gname having tag='$tag' order by mtime desc);"
1866 ## err PersonalGroupList= `echo $sql`
1867 echo "<h2>$tn</h2>"
1868 echo '<table class="b listgroup">'
1869 sq -header -html $db "$sql" \
1870 | sed "s,\(<TR><TD>\)\([0-9]*\):\([^ ]*\)</TD>,\1$href\2\">\3</a>,"
1871 echo '</table>'
1872 done
1873 echo '</div>'
1875 iconhref() (
1876 # $1=icon-file, $2=Href $3=title $4...=anchor
1877 data=`percenthex "$1"`
1878 ct=`file --mime-type - < "$1"|cut -d' ' -f2`
1879 ## err iconhref: \$1=$1 \$2=$2 \$3="$@"
1880 href=$2; title=$3; shift 3
1881 echo "<a href=\"$href\"><img title=\"$title\" src=\"data:$ct,$data\">$@</a>"
1883 iconhref2() (
1884 # $1=icon-file, $2=Href $3=title $4...=anchor
1885 src=$1
1886 href=$2; title=$3; shift 3
1887 echo "<a href=\"$href\"><img title=\"$title\" src=\"$src\">$@</a>"
1889 listentry() (
1890 # $1=user/group $2=SearchKeyword $3=condition(if any) $4=grprowid(if in grp)
1891 # Referring variable $iamowner=$grp to attach owner-request links
1892 ## err listentry: \$1=$1 \$2=$2 \$3=$3
1893 cond='' hiddens=''
1894 offset=`getpar offset`
1895 offset=${offset%%[!0-9]*}
1896 offset=$((offset + 0)) # change to numeric forcibly
1897 [ $offset -lt 0 ] && offset=0
1898 limit=30
1899 dir=`getcachedir "$1"`
1900 if [ x"$1" = x"user" ]; then
1901 hrb="$myname?home"
1902 deficon=person-default.png
1903 entity="ユーザ" tbl=user link=rowid nm=name # stage=mems
1904 [ -n "$4" ] && hiddens=`cgi_hidden grid $4`
1905 gcs=gecos
1906 else # if group
1907 hrb="$myname?grp"
1908 deficon=group-default.png
1909 entity="グループ" tbl=grp link=rowid nm=gname stage=grps
1910 gcs=name
1911 tagline=`grep :tag: $formdir/grp.def|cut -d: -f5-`
1912 if [ -n "$tagline" ]; then
1913 tagconv=`echo $tagline|sed 's/\([^= :]*\)=\([^= :]*\)/-D\2=\1/g'`
1914 ## err tagconv=$tagconv
1915 fi
1916 fi
1917 if [ ! -d $dir ]; then
1918 mkdir -p $dir
1919 fi
1920 if [ ! -s $dir/$deficon ]; then
1921 convert -geometry $thumbxy $imgdir/$deficon $dir/$deficon
1922 fi
1923 if [ -n "$2" ]; then
1924 cond="where nick like '%$2%' or b.name like '%$2%'"
1925 fi
1927 # XX: これ複雑すぎるかな。もっとシンプルにしたい。$3条件も。2015-07-08
1928 # grpは呼出し元の動的スコープ変数でよくないな...
1929 ##qgrp=`sqlquote $grp`
1930 getgrp="(select gname from grp where rowid=${rowid:--1})"
1931 sql="select a.rowid, a.$link,
1932 coalesce(b.$gcs, a.$nm) as nick,
1933 coalesce(b.gecos, a.$nm) /* If group, concat (Nusers) */
1934 || case when a.$nm in (select gname from grp)
1935 then printf('(%d名)',
1936 (select count(user) from grp_mem where gname=a.$nm))
1937 else ' <'||a.$nm||'>'
1938 end
1939 as name,
1940 b.tag,
1941 case when a.$nm in (select user from grp_adm
1942 where gname=$getgrp) then '(管理者)'
1943 when '$user' in (select user from grp_adm where gname=a.$nm)
1944 then '(ADMIN)'
1945 when '$user' in (select user from grp_mem where gname=a.$nm)
1946 then '(Member)'
1947 when '$iamowner' = '' then ''
1948 else ',not='||a.rowid end as ownerlink,
1949 CASE '$entity'
1950 WHEN 'グループ'
1951 THEN coalesce(
1952 (SELECT val FROM grp_s WHERE gname=a.$nm AND key='regmode'),
1953 'open')
1954 ||
1955 CASE WHEN '$user'
1956 IN (SELECT user FROM grp_mem WHERE gname=a.$nm)
1957 THEN ' ismember'
1958 ELSE ''
1959 END
1960 ELSE 'user'
1961 END regmode
1962 from $tbl a left join
1963 (select $nm as name,
1964 max(case key when 'gecos' then val end) as gecos,
1965 max(case key when 'tag' then val end) as tag,
1966 max(case key when 'mtime' then val end) as mtime
1967 from ${tbl}_s group by $nm)
1968 b on a.$nm=b.name $cond $3
1969 order by b.tag desc, b.mtime desc, a.rowid asc"
1970 # Give precedence to newer maintained groups (2016-09-24)
1971 # Note that mtime is stored only in grp_s.
1972 ## err LE:sql.1="$sql"
1973 total=`query "with x as ($sql) select count(*) from x;"`
1974 echo "${entity} 一覧" | html h2
1975 if [ $total -gt $limit ]; then
1976 echo '<div class="right">'
1977 cgi_form $stage <<EOF
1978 <label>次の語を含む${entity}で検索:
1979 `cgi_text kwd $kwd`</label>
1980 EOF
1981 echo '</div>'
1982 fi
1983 hiddens="$hiddens
1984 `cgi_hidden kwd \"$kwd\"`
1985 `cgi_hidden stage \"$stage\"`"
1986 cat<<EOF
1987 <p>${total}件中の$((offset+1))件めから${kwd:+" - 検索語: $kwd"}</p>
1988 EOF
1989 if [ $((offset+limit)) -lt $total ]; then
1990 nextbtn=$(
1991 cat<<EOF
1992 <div class="right clear"><form action="$myname" method="POST">
1993 `cgi_submit 次の${limit}件`
1994 $hiddens
1995 `cgi_hidden offset $((offset + limit))`</form></div>
1996 EOF
1998 fi
1999 if [ $offset -gt 0 ]; then
2000 prevbtn=$(
2001 cat<<EOF
2002 <form action="$myname" method="POST">
2003 `cgi_submit 前の${limit}件`
2004 $hiddens
2005 `cgi_hidden offset $((offset - limit))`</form>
2006 EOF
2008 fi
2009 pnbtn="$nextbtn$prevbtn"
2010 echo $pnbtn
2012 ## err ListEntry: `echo "$sql"\;`
2013 query "$sql limit $limit ${offset:+offset $offset};" \
2014 | while IFS='|' read id lnk name gecos tag ownerp type; do
2015 err name=$name owner=$ownerp lnk=$lnk
2016 err newlnk=$lnk regmode=$regmode
2017 icondir=$dir/$id
2018 files=`getvalbyid $tbl profimg $id $icondir`
2019 # Pick up only last icon
2020 echo "<div class=\"iconlist xy$thumbxy $type\">
2021 <p class=\"tag _$tag\">$tag</p>" \
2022 | _m4 $tagconv
2023 if [ -n "$files" ]; then
2024 icon=`echo "$files"|tail -1`
2025 iconhref2 "$icondir/$icon" "$hrb+$lnk" "$gecos"
2026 else
2027 iconhref "$dir/$deficon" "$hrb+$lnk" "$gecos"
2028 fi
2029 echo "<br>$name${ownerp:+<br>$ownerp}"
2030 echo "</div>"
2031 done
2032 echo ${pnbtn:+"<hr>$nextbtn$prevbtn"}
2034 listmember() {
2035 listentry user "$@"
2037 listgroup() {
2038 listentry group "$@"
2040 hexteams() { # $1=gname, $2(optional)=user
2041 cond=${2:+" AND user='$2'"}
2042 query "SELECT DISTINCT hex(val) FROM grp_mem_m
2043 WHERE gname='$1' AND key='team'$cond;"
2045 showgroup() { # $1=group-rowid
2046 if [ -z "$1" ]; then
2047 grid=`getpar grid`
2048 grid=${grid%%[!0-9]*}
2049 [ -n "$grid" ] && grp=`getgroupbyid $grid`
2050 else
2051 grid=$1
2052 fi
2053 grp=`getgroupbyid $grid`
2054 qgrp=`sqlquote $grp`
2055 ## err showgroup2: grp=$grp qgrp="[$(sqlquote $grp)]"
2056 if isgroup "$grp"; then
2057 tf=$tmpd/title.$$
2058 bodyclass=`query "SELECT val FROM grp_s
2059 WHERE gname=$qgrp AND key='regmode';"`
2060 if ismember "$user" "$grp"; then
2061 ismember="ismember"
2062 qgrp=`sqlquote $grp`
2063 bodyclass="$bodyclass${bodyclass:+ }ismember"
2064 else
2065 ismember="" # bodyclass="group"
2066 fi
2067 bodyclass="$bodyclass grouphome"
2068 echo "グループ $grp" > $tf
2069 showgroupsub $formdir/grp.def "$grid" | \
2070 _m4 -D_TITLE_="spaste(\`$tf')" \
2071 -D_FORM_="syscmd(\`cat')" \
2072 -D_BODYCLASS_="$bodyclass" \
2073 -D_DUMPTABLE_="" \
2074 $htmlheader $layout/form+dump.m4.html
2075 # $htmlheader is defined in grp()
2076 else # if $grp is removed at par2table
2077 listgroup
2078 fi
2080 showgroupsub() {
2081 # $1=def-file $2=group-rowid
2082 # Using $ismember
2083 rowid=$2
2084 grp=`getgroupbyid $2`
2085 qgrp=`sqlquote $grp`
2086 td=`getcachedir grp/"$2"`
2087 #rowid=`sq $db "select rowid from grp where gname=$qgrp"`
2088 if [ -z "$rowid" ]; then
2089 #rowid=`sq $db "select rowid from grp where rowid=$grp"`
2090 #grp=`sq $db "select gname from grp where rowid=$grp"`
2091 echo "showgroupsub: invalid argument($1 $2)" | html p
2092 return
2093 fi
2094 val=`getvalbyid grp profimg $rowid $tmpd`
2095 enticond="gname=$qgrp"
2096 img=`query "SELECT type FROM grp_m WHERE $enticond LIMIT 1;"`
2097 if [ -n "$img" ]; then
2098 cat<<-EOF
2099 <p class="groupimg">
2100 `imgsrc_cache $td/main grp_m "$enticond" M`</p>
2101 EOF
2102 fi
2103 echo "<div class=\"noprofimg\">"
2104 viewtable $1 grp $rowid
2105 echo "</div>"
2106 if isgrpowner "$user" "$grp"; then
2107 echo "<p><a href=\"?groupconf+$rowid\">グループ情報の編集</a>"
2108 iamowner=$rowid
2109 colmd=" mode"
2110 fi
2111 if [ -n "$ismember" ]; then
2112 echo "${iamowner:+ / }<a href=\"?blog+$rowid\">グループの新規話題作成</a>"
2113 echo "/ <a href=\"?grpaction+$rowid\">メンバーを個別選択しての操作</a></p>"
2114 # div.fold input[type="checkbox"]:checked ~ div {display: block;}
2115 cat<<EOF
2116 <form action="?send2mem" method="POST" enctype="multipart/form-data">
2117 <div class="fold clear">
2118 `cgi_checkbox send yes id="send"`<label
2119 for="send">グループ全員にメッセージ送信</label>
2120 <div>
2121 `cgi_textarea message "" "cols=60"`
2122 `cgi_submit 送信`
2123 `cgi_reset リセット`
2124 </div>
2125 `cgi_hidden grp $rowid`
2126 </div></form>
2127 EOF
2128 fi
2129 # 加入ボタン + 加入者リスト
2130 if [ -n "$ismember" ]; then
2131 ismem='checked' state="(参加中)"
2132 else
2133 nomem='checked' state="(現在非加入)"
2134 fi
2135 # このグループでの加入アドレス
2136 eml=`query "select val from grp_mem_s where gname=$qgrp and user='$user' \
2137 and key='email';"`
2138 ##err EML: "select val from grp_mem_s where gname='$2' and user='$user' \
2139 ## and key='email';"
2140 ##err email=$eml
2141 cat <<EOF
2142 <div class="fold clear">
2143 `cgi_checkbox reg yes id="reg"`<label
2144 for="reg">自身の加入状態を操作する</label>$state
2145 <div>
2146 EOF
2147 cgi_form grp <<EOF
2148 <p>このグループに</p>
2149 <table class="b">
2150 <tr><th>メンバーとして</th><td>
2151 <label>`cgi_radio joingrp "yes" $ismem`参加</label> /
2152 <label>`cgi_radio joingrp "no" $nomem`参加しない</label></td></tr>
2153 <tr><th>参加する場合のメイルアドレス<br>
2154 <small>(メインのアドレスとは違うものにする場合に記入<br>
2155 同じでよい場合は空欄に)</small></th>
2156 <td>`cgi_text email $eml`</td></tr>
2157 </table>
2158 `cgi_hidden grp $rowid`
2159 EOF
2160 if [ x`getgroupattr $grp regmode` = x'moderated' -a -z "$ismem" ]; then
2161 echo "moderated (承認加入の)グループなので実際に参加できるのは
2162 グループ管理者が承認操作をした後になります。" | html p 'class="warn"'
2163 fi
2164 echo '</div></div>'
2165 echo '<h2>話題一覧</h2>'
2166 cgi_form searchart<<EOF
2167 <label>`cgi_text kwd`という語を含むコメントを検索</label>
2168 `cgi_hidden owner $grp`
2169 EOF
2170 cond="where a.id in (select id from blog_s where key='owner' and val=$qgrp) order by ctime desc"
2171 DT_CHLD=article:blogid \
2172 DT_VIEW=replyblog dumptable html blog \
2173 "ctime team title heading$colmd" "$cond"
2175 getgname="(select gname from grp where rowid=$rowid)"
2176 c="group by a.name having a.name in (select user from grp_mem where gname=$getgname)"
2177 cm="?commission+$rowid"
2178 thumbxy=50x50 listmember "" "$c" "$rowid" \
2179 |sed -e "s|\(<br>\),not=\(.*\)|\1|" # 間違って押しやすい
2180 # team list
2181 hexteams=`hexteams "$grp"`
2182 if [ -n "$hexteams" ]; then
2183 echo "チーム一覧" | html h2
2184 echo '<div class="dumptable"><table class="b">'
2185 sq $db -html -header<<-EOF
2186 SELECT val TEAM,
2187 group_concat((SELECT gecos FROM gecoses WHERE name=user), ',')
2188 MEMBERS
2189 FROM grp_mem_m WHERE gname=$qgrp AND key='team' GROUP BY val;
2190 EOF
2191 echo '</table></div>'
2192 fi
2194 grp_getbodyclass() {
2195 # Get css class name for document.
2196 # `moderated' for moderated groups
2197 # `ismember' for groups where user belongs
2198 # $1=GroupName (w/o quote)
2199 # $user=userNameCurrentlyLogin
2200 ## err grp_getbodyclass: 1="$1"
2201 qgrp=`sqlquote "$1"`
2202 query<<-EOF
2203 SELECT coalesce(
2204 (SELECT val FROM grp_s WHERE gname=$qgrp AND key='regmode'),
2205 'open')
2206 ||
2207 CASE WHEN '$user'
2208 IN (SELECT user FROM grp_mem WHERE gname=$qgrp)
2209 THEN ' ismember'
2210 ELSE ''
2211 END;
2212 EOF
2214 grpaction() { # $1=group-rowid
2215 err GRP_ACTION:IN
2216 grid=${1:-`getpar grp`}
2217 grp=`getgroupbyid "$grid"`
2218 if [ -z "$grp" ]; then
2219 echo "無効な指定です。" | html p; return
2220 fi
2221 if ! ismember $user $grp; then
2222 echo "加入者のみに許可された操作です。" | html p; return
2223 fi
2224 echo "グループ $grp 個別選択操作" \
2225 | _m4 -D_TITLE_="syscmd(\`cat')" \
2226 -D_BODYCLASS_="`grp_getbodyclass \"$grp\"`" \
2227 $layout/html.m4.html
2229 isowner=""
2230 isgrpowner "$user" "$grp" && isowner="yes"
2231 usel=`getpar usel`
2232 if [ -n "$usel" ]; then
2233 uids=$(echo `echo $usel`|tr ' ' ',')
2234 ## err grpaction-1: grp=$grp, `echo $sql`
2235 text=`getpar text`
2237 rm=`getpar rm` cfm=`getpar confirm`
2238 ## err rm=$rm cfm=$cfm
2239 if [ x"$rm" = x"yes" ]; then
2240 if [ "$isowner" ]; then
2241 if [ x"$rm$cfm" = x"yesyes" ]; then
2242 # Eliminate
2243 cond="where gname=(select gname from grp where rowid=$grid) and user in (select name from user where rowid in ($uids))"
2244 for tbl in grp_mem grp_mem_s grp_mem_m; do
2245 sql="delete from $tbl $cond;"
2246 # echo "sql=$sql"
2247 query "$sql"
2248 err rmGRPuser "$sql"
2249 done
2250 num=`query "select count(*) from user where rowid in ($uids);"`
2251 #err num=$num
2252 if [ 0$num -gt 0 ]; then
2253 sql="select coalesce(b.val,a.name) from user a left join \
2254 user_s b on a.name=b.name and key='gecos' where a.rowid in ($uids);"
2255 # err `echo "$sql"`
2256 html pre<<EOF
2257 以下の${num}名のグループ $grp 登録を解除しました。
2258 `query "$sql"`
2259 EOF
2260 fi
2261 else
2262 echo "確認のチェックがないのでやめておきます。" | html p
2263 return
2264 fi
2265 else # not Group Owner
2266 echo "グループ管理者でないのでメンバー操作はできません。" | html p
2267 return
2268 fi
2269 cat<<EOF
2271 EOF
2272 elif [ x"$rm" = x"send" ]; then # if sendmsg mode
2273 if [ -z "$text" ]; then # if msg is empty
2274 echo "なにかメッセージを..." | html p
2275 return 0
2276 fi
2277 gecos=`gecos $user`
2278 mkfrom=`getpar mkfrom`
2279 if [ x"$mkfrom" = x"yes" ]; then
2280 safegc=`echo "$gecos" | tr -d '<>@'`
2281 myuid=`query "SELECT rowid FROM user WHERE name='$user';"`
2282 fromad=`email4groupbyuid "$grp" "$myuid"`
2283 mail_from="$safegc <$fromad>"
2284 else
2285 mail_from="$admin"
2286 fi
2287 MAIL_FROM=$mail_from \
2288 smail "`email4groupbyuid "$grp" $usel` $user" \
2289 "$gecos さんからのメッセージ" <<EOF
2290 $url
2291 のグループ「$grp」のメンバーである $gecos さんから、
2292 あなた宛へのメッセージです。
2293 ----------------------------------------------------------
2294 $text
2295 EOF
2296 if [ $? = 0 ]; then
2297 echo "Note: 以下のメンバーにメッセージを送信しました。" | html p
2298 sql="select coalesce(b.val, a.name) from
2299 (select name from user where rowid in ($uids)) a
2300 left join user_s b on a.name=b.name and b.key='gecos';"
2301 html pre<<EOF
2302 `query "$sql"`
2303 (送信者である $gecos さんも含まれます)
2304 EOF
2305 err SendDone: `echo $sql`
2306 fi
2307 elif [ x"$rm" = x"commission" ]; then
2308 grp_reg_adm $grid $usel
2309 elif [ x"$rm" = x"addteam" ]; then
2310 team=`getpar team|sed "s/'/''/g"` # for single quotation
2311 newteam=`echo "$team"|tr -d ,`
2312 if [ x"$team" != x"$newteam" ]; then
2313 echo "チーム名に使えない文字を除去しました" | html p
2314 team=newteam
2315 fi
2316 if [ -z "$team" -o x"$team" = x"なし" ]; then
2317 cat<<-EOF | html p
2318 有効なチーム名を入力してください。
2319 カンマだけ、「なし」という名前は使えません。
2320 EOF
2321 echo "有効なチーム名を入力してください。" | html p
2322 else
2323 grp_add_team $grid "$team" $usel
2324 fi
2325 elif [ x"$rm" = x"rmteam" ]; then
2326 if [ x"yes" = x"`getpar teamconfirm`" ]; then
2327 rmteam=`getpar rmteam|sed "s/'/''/g"`
2328 if [ -n "`query \"SELECT val FROM grp_mem_m WHERE\
2329 gname='$grp' AND user='$user' AND key='team'\
2330 AND val='$rmteam';\"`" ]; then
2331 grp_rm_team $grid "$rmteam" $usel
2332 else
2333 echo "所属していないチームの除去操作はできません。"|html p
2334 fi
2335 else
2336 echo "確認チェックなしなのでチーム除去しませんでした。"|html p
2337 fi
2338 fi
2339 fi
2340 # New entry
2341 sql="select /* Ahh, ugly SQL, I wanna fix... */
2342 case
2343 when (select user from grp_adm where
2344 gname=(select gname from grp where rowid=$grid)
2345 and user=a.name) is not null
2346 then 'k'
2347 else ''
2348 end || a.rowid||
2349 ','||a.gecos as NAME,
2350 (SELECT count(author) /* Put post count for scoring 2016-08-01 */
2351 FROM article NATURAL JOIN article_s
2352 WHERE blogid IN
2353 (SELECT id FROM blog_s
2354 WHERE key='owner'
2355 AND val=(SELECT gname FROM grp where rowid=$grid))
2356 AND author=a.name AND key='text')
2357 as POST,
2358 (SELECT group_concat(val, ',')
2359 FROM grp_mem_m
2360 WHERE gname='$grp' AND user=a.name AND key='team') as TEAM
2361 FROM
2362 gecoses a
2363 WHERE name in (select user from grp_mem where
2364 gname=(select gname from grp where rowid=$grid))
2365 ORDER by a.gecos;"
2366 ## err grpaction: "`echo \"$sql\"`"
2367 tf=$tmpd/title.$$
2368 echo "グループ[<a href=\"?grp+$grid\">$grp</a>]参加メンバーに対する操作" > $tf
2369 cmmsg="`cgi_radio rm commission id=\"cmadmin\"`<label
2370 for=\"cmadmin\">グループ管理者委任</label>
2371 <div><p>このグループでの全権を付与します。信頼できる人に託してください。
2372 </p></div>"
2373 excmsg="`cgi_radio rm yes id=\"conf\"`<label
2374 for=\"conf\">グループ登録解除</label>
2375 <div>本当に消します! `cgi_checkbox confirm yes` 確認
2376 <p>この操作による通知は本人に行きません。
2377 あらかじめ通知するか、登録解除してよい状況かしっかり確認してください。</p>
2378 </div>"
2379 # Get team list to which current user belongs into $hexteams
2380 myhexteams=$(hexteams "$grp" "$user")
2381 allhexteams=$(hexteams "$grp")
2382 if [ -n "$myhexteams" ]; then
2383 rmteammsg="`cgi_radio rm rmteam 'id=\"cmrmteam\"'`<label
2384 for=\"cmrmteam\">チーム属性除去</label>
2385 <div>チーム属性:`cgi_select_h rmteam \"2d2d2d\" $myhexteams`
2386 を除去します: `cgi_checkbox teamconfirm yes` 確認
2387 <p>この操作による通知は本人に行きません。
2388 あらかじめ通知するか、登録解除してよい状況かしっかり確認してください。</p>
2389 </div><!-- end of $rmteammsg -->
2391 fi
2392 b1='<label> <input type="checkbox" name="usel" value="'
2393 ba='<label class="admin"><input type="checkbox" name="usel" value="'
2394 #b2='"> <span>' b3='</span></label>'
2395 # | sed -e "s|^\(<TR><TD>\)k\([0-9]*\),\([^<]*\)|\1$ba\2$b2\3$b3|" \
2396 # -e "s|^\(<TR><TD>\)\([0-9]*\),\([^<]*\)|\1$b1\2$b2\3$b3|" \
2397 lnk='"> <span>\3</span></label> [<a href="?home+\2">HOME</a>]'
2398 cgi_form grpaction<<EOF \
2399 | sed -e "s|^\(<TR><TD>\)k\([0-9]*\),\([^<]*\)|\1$ba\2$lnk|" \
2400 -e "s|^\(<TR><TD>\)\([0-9]*\),\([^<]*\)|\1$b1\2$lnk|" \
2401 | _m4 -D_TITLE_="spaste(\`$tf')" \
2402 -D_SUBTITLE_="チェック後操作ボタン" \
2403 -D_FORM_="syscmd(cat)" -D_DUMPTABLE_="" \
2404 $layout/form+dump.m4.html
2405 <p>下でチェックした人を対象として:</p>
2406 <div class="foldtabs">
2407 `cgi_radio rm addteam 'id="cmteam"'`<label
2408 for="cmteam">同じチーム属性を付与</label>
2409 <div>チーム名:`cgi_text team "" 'id="inteam" list="teams"'`
2410 `cgi_datalist_h teams $allhexteams`
2411 </div>
2412 ${rmteammsg}
2413 `cgi_radio rm send id="sendmsg"`<label
2414 for="sendmsg">メッセージ送信</label>
2415 <div>
2416 `cgi_checkbox mkfrom yes 'id="mkfrom" checked'`<label for="mkfrom"
2417 >差出人を自分に(チェックを外すと相手が返事できない)</label><br>
2418 `cgi_textarea text "" cols=40`
2419 </div>
2420 ${isowner:+$cmmsg$excmsg}
2421 `cgi_radio rm close id="x"`<label for="x">×</label>
2422 </div>
2423 <h4>$grp 参加者一覧</h4>
2424 <table class="td2r">
2425 `sq $db -header -html "$sql"`
2426 </table>
2427 `cgi_hidden grp $grid`
2428 EOF
2430 crview4article() { # $1=rowid of blog, $2(optional)=extra SQL
2431 # Create TEMPORARY VIEW
2432 query<<EOF
2433 CREATE TEMPORARY VIEW writeusers AS
2434 SELECT DISTINCT author FROM article
2435 WHERE id in (
2436 select id from article where blogid=(select id from blog where rowid=$1)
2437 );
2438 CREATE TEMPORARY VIEW movablegroups AS
2439 SELECT g.rowid growid , g.gname
2440 FROM (SELECT grp.rowid, grp.gname FROM grp JOIN grp_mem gm
2441 ON grp.gname=gm.gname -- そのユーザが属している
2442 AND user='$user') g -- グループに絞る
2443 WHERE (SELECT author FROM writeusers
2444 EXCEPT
2445 SELECT user FROM grp_mem gm WHERE gm.gname = g.gname)
2446 IS NULL;
2447 $2
2448 EOF
2450 sql4readableblogs() {
2451 # Create view of blogs that can be readable to $user
2452 # Blog is readable when:
2453 # 1: blog owner is an user
2454 # 2: else, 2.1: owner-group where the $user belongs
2455 # 2.2: else, owner-group is not moderated
2456 # blog(id, author), blog_s(id, key='owner', val= ->owner)
2457 cat<<EOF ## | tee tmp/sql.out
2458 CREATE TEMPORARY VIEW readableblogs AS
2459 SELECT blog.rowid rid, id, author
2460 FROM blog
2461 NATURAL JOIN
2462 (SELECT id, val owner FROM blog_s WHERE key='owner') bs
2463 WHERE CASE WHEN (SELECT name FROM user where name=bs.owner) IS NOT NULL
2464 THEN 1 -- blog owner is an user, READABLE
2465 WHEN (SELECT val FROM grp_s
2466 WHERE gname=bs.owner AND key='regmode') = 'moderated'
2467 AND
2468 (SELECT user FROM grp_mem
2469 WHERE gname=bs.owner AND user='$user') IS NULL
2470 THEN 0
2471 ELSE 1
2472 END;
2473 EOF
2475 editheading() { # $1=rowid-of-heading
2476 rowid=${1%%[!A-Z0-9a-z_]*}
2477 if [ -z "$rowid" ]; then
2478 echo "話題番号が未指定です。" | html p
2479 return
2480 fi
2481 owner=`getvalbyid blog owner $rowid`
2482 title=`getvalbyid blog title $rowid`
2483 GF_ACTION="?blog" edittable $formdir/blog.def blog $rowid \
2484 | _m4 -D_TITLE_="修正" \
2485 -D_SUBTITLE_="[$title]@$owner" -D_DIARY_="" \
2486 -D_BLOGS_="" -D_DUMPTABLE_="" \
2487 -D_FORM_="syscmd(\`cat')" \
2488 $layout/html.m4.html $layout/form+dump.m4.html
2489 # Move to group
2490 if isuser "$owner"; then
2491 crview4article $rowid
2492 n=`query "SELECT count(*) FROM writeusers;"`
2493 ## err N=$n
2494 if [ $((n)) -gt 0 ]; then
2495 ## err ROWID=$rowid
2496 sql="SELECT growid || ':' || gname FROM movablegroups;"
2497 cat<<-EOF
2498 <div class="fold">
2499 `cgi_checkbox mv send id="mv"`<label
2500 for="mv">この話題をグループ所有に移動する</label>
2501 <div>
2502 <form action="?mvart" method="POST" enctype="multipart/form-data">
2503 移動先グループ:
2504 <select name="mv2grp">
2505 EOF
2506 query ".mode html"
2507 query<<-EOF |
2508 $sql
2509 .mode list
2510 EOF
2511 sed -e '/<\/TR>/d' -e 's,<TR>,,' -e 's,TD>,option>,g' \
2512 -e 's,n>\([0-9]*\):\(.*\)<,n value="\1">\2<,'
2513 cat<<-EOF
2514 </select>
2515 <p>(移動できるグループは、この「話題」に書き込んでいる人全てが
2516 そのグループに加入しているものに限られます)</p>
2517 <p>`cgi_checkbox cfm yes`<label>確認
2518 (この操作は元に戻すことができません)</label></p>
2519 `cgi_hidden blogrowid $rowid`
2520 `cgi_submit 移動`
2521 `cgi_reset Reset`
2522 </form>
2523 </div>
2524 </div>
2525 EOF
2526 fi
2527 # end of isuser "$owner"
2528 elif { hexteams=$(hexteams "$owner" ) # blog is of GROUP
2529 [ -n "$hexteams" ];}; then
2530 none="`echo なし|hexize`"
2531 cat<<-EOF
2532 <div class="fold">
2533 `cgi_checkbox mv2team send id="mv2team"`<label
2534 for="mv2team">この話題を以下のチームのものにする</label>
2535 <div><p>現在の所属チーム設定:
2536 `query "SELECT
2537 coalesce((SELECT val FROM blog_s
2538 WHERE id=(SELECT id FROM blog WHERE rowid=$rowid)
2539 AND key='team'),
2540 ':なし');"`</p>
2541 <form action="?mvart" method="POST" enctype="multipart/form-data">
2542 移動先チーム: `cgi_select_h mv2team $none $hexteams`
2543 <p>`cgi_checkbox cfm yes`<label>確認</label></p>
2544 `cgi_hidden blogrowid $rowid`<br>
2545 `cgi_submit 移動`
2546 `cgi_reset Reset`
2547 </form></div></div>
2548 EOF
2549 fi
2551 mvart() { # move diary to some group or team
2552 # or move blog of group to team which belong to the group
2553 blogrowid=`getpar blogrowid`
2554 cfm=`getpar cfm`
2555 ##### echo move blog:$blogrowid to $mv2grp | html p
2556 blogrowid=${blogrowid%%[!A-Z0-9a-z_]*} # Purify
2557 . ./s4-blog.sh
2558 if [ -z "$blogrowid" ]; then
2559 echo "無効な指定です(mvart)。" | html p
2560 return
2561 elif [ x"$cfm" != x"yes" ]; then
2562 echo "記事移動の確認にチェックがないので通常表示に戻ります。" | html p
2563 elif { mv2grp=`getpar mv2grp`
2564 mv2grp=${mv2grp%%[!A-Z0-9a-z_]*} # Purify
2565 [ -n "$mv2grp" ]; }; then
2566 crview4article $blogrowid
2567 ########## TRANSACTION BEGIN
2568 query "BEGIN;"
2569 n=`query "SELECT count(*) FROM writeusers;"`
2570 ## err Nwriteuser=$n
2571 if [ $((n)) -gt 0 ]; then
2572 query<<-EOF
2573 UPDATE blog_s SET val=(SELECT gname FROM grp WHERE rowid=$mv2grp)
2574 WHERE key='owner'
2575 AND id=(SELECT id FROM blog WHERE rowid=$blogrowid)
2576 AND $mv2grp IN (SELECT growid FROM movablegroups);
2577 EOF
2578 fi
2579 query "END;"
2580 ########## TRANSACTION END
2581 elif { mv2team=`getpar mv2team|sed "s/'/''/g"`
2582 [ -n "$mv2team" ];}; then
2583 # blog owner can move it to ANY team
2584 case "$mv2team" in
2585 'なし')
2586 cat<<-EOF
2587 DELETE FROM blog_s
2588 WHERE id=(SELECT id FROM blog WHERE rowid=$blogrowid)
2589 AND key='team';
2590 EOF
2591 ;;
2592 "") ;;
2593 *)cat<<-EOF
2594 BEGIN;
2595 REPLACE INTO blog_s(id, key, val)
2596 VALUES((SELECT id FROM blog WHERE rowid=$blogrowid),
2597 'team', '$mv2team');
2598 REPLACE INTO blog_s(id, key, val)
2599 VALUES((SELECT id FROM blog WHERE rowid=$blogrowid),
2600 'notify', 'all'); -- Change notify to all
2601 END;
2602 EOF
2603 esac | query
2604 fi
2605 blog_reply $blogrowid
2606 echo yes | html p
2608 editart() { # $1=article-rowid $2=blogrowid
2609 rowid=${1%%[!A-Z0-9a-z_]*}
2610 blogrowid=${2%%[!A-Z0-9a-z_]*}
2611 if [ -z "$rowid" -o -z "$blogrowid" ]; then
2612 echo "表示する記事番号が未指定です。" | html p
2613 return
2614 fi
2615 owner=`getvalbyid blog owner $blogrowid`
2616 title=`getvalbyid blog title $blogrowid`
2617 author=`getvalbyid article author $rowid`
2618 ## err EDITart: owner=$owner, author=$author
2619 if isgrpowner $user $owner; then
2620 : EDIT OK
2621 elif [ x"$owner" != x"$user" -a x"$author" != x"$user" ]; then
2622 echo "本人か所有者しか編集できません." | html p
2623 return
2624 fi
2625 aid=`query "select id from article where rowid=$rowid;"`
2626 tmpout=$tmpd/editart.$$.out
2627 GF_ACTION="?replyblog+$blogrowid#$aid" \
2628 edittable $formdir/article.def article $rowid \
2629 > $tmpout
2630 rm -f /tmp/editart.out
2631 # Cannot use pipelining to m4 with genform() because of stdin stack
2632 _m4 -D_TITLE_="コメントの修正" -D_DIARY_="" \
2633 -D_FORM_="syscmd(cat $tmpout)" \
2634 -D_SUBTITLE_="`gecos $owner`の「$title」" \
2635 -D_BLOGS_= -D_DUMPTABLE_= \
2636 $layout/html.m4.html $layout/form+dump.m4.html
2638 send2mem() {
2639 rowid=`getpar grp`
2640 if [ -z "$rowid" ]; then
2641 echo "グループが未指定です。" | html p
2642 return
2643 fi
2644 message=`getpar message`
2645 if [ -z "$message" ]; then
2646 echo "文章を入れてください。" | html p
2647 return
2648 fi
2649 grp=`getgroupbyid $rowid`
2650 members=`collectemail $grp`
2651 # smail rcpt subj (file)
2652 smail "$members" "グループ $grp 宛メッセージ(from `gecos $user`)" <<EOF
2653 $urlbase?grp+$rowid
2654 グループ $grp に所属する
2655 `gecos $user` さんよりメッセージ:
2657 $message
2658 EOF
2659 cat<<EOF
2660 <p>以下の宛先に送信しました。</p>
2661 <pre>
2662 $members
2663 </pre>
2664 <p><a href="?grp+$rowid">グループ $grp</a>に戻る。</p>
2665 EOF
2667 joingrpadmit() {
2668 # $1=yes/no $2=session-key
2669 if [ -z "$2" ]; then
2670 echo "bye bye" | html p; return
2671 fi
2672 t_usr=`session=$2 getpar user`
2673 t_grp=`session=$2 getpar group`
2674 ## err joingrpadmit: t_usr=$t_usr, t_grp=$t_grp
2675 _m4 -D_TITLE_="joingrp" $layout/html.m4.html
2676 if [ -z "$t_usr" -o -z "$t_grp" ]; then
2677 echo "無効な加入依頼です。" | html p
2678 echo "有効期限が切れたか、
2679 他の管理者がいる場合は処理済みの可能性があります。" | html p
2680 return
2681 fi
2682 if ! isgrpowner "$user" $t_grp; then
2683 echo "グループ管理者のみの機能です。" | html p; return
2684 fi
2685 case $1 in
2686 yes) joingrp "$t_grp" "$t_usr" yes ;;
2687 no) joingrp "$t_grp" "$t_usr" no ;;
2688 *)
2689 echo "無効な指定です($1)。" | html p
2690 return ;;
2691 esac
2692 gid=$(query "select rowid from grp where gname=`sqlquote $t_grp`;")
2693 rcpts="`getgroupadminmails $t_grp` $user"
2694 ## err admit: msgdir=$msgdir, rcpts="["$rcpts"]"
2695 body="グループ <a href=\"?grp+$gid\">$t_grp</a>
2696
2697 $t_usr
2698 `[ x$1 = xyes ] && echo 'を追加' || echo 'の解除操作を'`
2699 しました。"
2700 (echo "$body"; echo; echo "$url?grp+$gid") | smail "$rcpts" "joingrp $1"
2701 query "delete from session where id='$2';"
2702 echo "$body" | html p
2705 joingrprequest() {
2706 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
2707 jss="joingrp-`date +%s`-`genrandom 12`"
2708 addsession $jss +${memoplimitdays}days
2709 query "replace into par values('$jss', 'group', 'string', `sqlquote $1`),
2710 ('$jss', 'user', 'string', `sqlquote $user`);"
2711 smail "$(collectemail `getgroupadmins $1`)" "Join request to $1"<<EOF
2712 $url
2713 $user さんから
2714 グループ $1
2715 に加入依頼がありました。
2717 承認する:
2718 $urlbase?joingrpadmit+yes+$jss
2720 白紙に戻す:
2721 $urlbase?joingrpadmit+no+$jss
2722 EOF
2723 echo "管理者に加入依頼を出しました。
2724 ${memoplimitdays}日以内に加入承認操作がされれば加入できますが、
2725 グループ運用方針に懸かることですので直接の問い合わせが重要です。" | html p
2727 joingrp() {
2728 # $1=group $2=user $3=yes/no $4=email(if any $5=AsAdmin)
2729 ## err joingrp: \$1=$1 \$2=$2 \$3=$3 \$4=$4
2730 if isgrpowner "$user" "$1"; then
2731 isowner="yes"
2732 elif [ -n "$5" ]; then
2733 isowner="yes"
2734 else
2735 isowner=""
2736 fi
2737 ## err jg:isgrpowner: isowner="$isowner"
2738 if [ -n "$isowner" ]; then
2739 : # GROUP OWNER CAN DO EVERYTHING ABOUT REGISTRATION/RETIREMENT
2740 elif [ x"$2" != x"$user" ]; then # if user is not login user
2741 echo "本人か、グループ管理者しか加入操作はできません。" | html p
2742 return
2743 elif [ x"$3" = x"no" ]; then
2744 : # Do not pursue those who leave
2745 elif [ x"$3" = x"yes" ] && ismember "$user" "$grp"; then
2746 : # Member can change own email address for the joining moderated group
2747 else # adding user is $user itself
2748 case `getgroupattr $1 regmode` in
2749 moderated)
2750 joingrprequest "$@" # Request only
2751 return
2752 ;;
2753 *)
2754 ;;
2755 esac
2756 fi
2757 qgname=`sqlquote $1`
2758 cond="where gname=$qgname and user='$2'"
2759 if [ x"$3" = x"yes" ]; then
2760 query "replace into grp_mem values($qgname, '$2');"
2761 if [ -n "$4" ]; then
2762 if msg=`emaildomaincheck "$4"`; then
2763 query "replace into grp_mem_s values($qgname, '$user', 'email', \
2764 'string', '$4', NULL);"
2765 else
2766 echo $msg
2767 fi
2768 else
2769 query "delete from grp_mem_s $cond and key='email';"
2770 fi
2771 if [ -n "$5" ]; then # as ADMIN
2772 # Coming here means newly created group
2773 sql="select case\
2774 when (select count(*) from grp_mem where gname=$qgname)=1\
2775 then (select user from grp_mem\
2776 where gname=$qgname and user='$user')\
2777 else '' end; "
2778 err NewGrpChk: $sql
2779 if [ -n "`query \"$sql\"`" ]; then
2780 ## err ADMIN: "replace into grp_adm values($qgname, '$user');"
2781 query "replace into grp_adm values($qgname, '$user');"
2782 fi
2783 fi
2784 else
2785 query "delete from grp_mem $cond;
2786 delete from grp_mem_s $cond;
2787 delete from grp_mem_m $cond;"
2788 fi
2790 grp_add_team() (
2791 # $1=grp-rowid $2=team $3...=user-rowid(s)
2792 grp=`getgroupbyid $1`
2793 team=$2; shift; shift
2794 [ -z "$grid" -o -z "$team" -o -z "$1" ] && return
2795 { echo "BEGIN;"
2796 for user; do
2797 echo "REPLACE INTO grp_mem_m(gname, user, key, type, val) VALUES(\
2798 '$grp',\
2799 (SELECT name FROM user WHERE rowid=$user),\
2800 'team', 'string', '$team');"
2801 done
2802 echo "END;"
2803 } | query
2805 grp_rm_team() (
2806 # $1=grp-rowid $2=team $3...=user-rowid(s)
2807 grid=$1
2808 qgrp=$(sqlquote "`getgroupbyid $grid`")
2809 team=$2; shift; shift
2810 [ -z "$grid" -o -z "$team" ] && return
2811 { echo "BEGIN;"
2812 for user; do
2813 echo "DELETE FROM grp_mem_m\
2814 WHERE gname=$qgrp \
2815 AND user=(SELECT name FROM user WHERE rowid=$user)\
2816 AND key='team' AND val='$team';"
2817 done
2818 cat<<-EOF
2819 DELETE FROM blog_s
2820 WHERE rowid=(
2821 SELECT rowid
2822 FROM blog_s a
2823 WHERE key='team'
2824 AND id IN (SELECT id FROM blog_s WHERE key='owner' AND val=$qgrp)
2825 AND NOT EXISTS (SELECT * FROM grp_mem_m
2826 WHERE key='team' AND val=a.val -- a.val=team
2827 AND gname = (SELECT val FROM blog_s b
2828 WHERE a.id=b.id AND key='owner')
2829 ));
2830 EOF
2832 echo "END;"
2833 } | query
2835 grp_reg_adm() {
2836 # $1=grp-rowid $2...=user-rowid
2837 grid=$1
2838 grp=`getgroupbyid "$1"`
2839 if [ -z "$grp" ]; then
2840 echo "無効なグループIDです" | html p; return
2841 fi
2842 if ! isgrpowner $user "$grp"; then
2843 echo "$grp グループの管理者しかこの操作はできません。" | html p; return
2844 fi
2845 shift
2846 for urid; do
2847 newadm=`query "select name from user where rowid=$urid;"`
2848 if [ -z "$newadm" ]; then
2849 echo "指定ユーザIDがおかしいようです。" | html p; return
2850 fi
2851 err GRP_reg_adm: "replace into grp_adm values(`sqlquote $grp`, '$newadm');"
2852 err ismember $newadm $grp
2853 if ismember $newadm $grp; then
2854 # OK, go ahead
2855 getgname="(select gname from grp where rowid=$grid)"
2856 query "replace into grp_adm values($getgname, '$newadm');"
2857 # confirm insertion
2858 sql="select * from grp_adm where gname=$getgname and user='$newadm'"
2859 if [ -n "`query \"$sql;\"`" ]; then
2860 echo "追加完了: $newadm" | html p
2861 else
2862 echo "追加失敗($1 $urid)" | html p
2863 fi
2864 fi
2865 showgroup $grid
2866 done
2868 dumptable() {
2869 # $1=mode $2=Table $3=column-list-of-*_s(defaults to *) $4=conditions(if any)
2870 # textのフィールドだけ全てダンプにしたほうがいいか
2871 # $DT_VIEW sets link
2872 # 6/17の次: editリンクじゃなくてスレッドVIEWリンクでいいんちゃう?
2873 ### elink="<a href=\"$myname?edittable+$2+\\2\">EDIT</a>"
2874 VIEW=${DT_VIEW-replyblog}
2875 if [ -n "$VIEW" ]; then
2876 dvlink=" <a href=\"$myname?$VIEW+\\2\\3\">VI</a><a href=\"$myname?$VIEW+\\2#bottom\">EW</a>"
2877 fi
2878 # $DT_CHLD=ChildTable:BindColumn
2879 if [ -n "$DT_CHLD" ]; then
2880 _t=${DT_CHLD%:*} _i=${DT_CHLD#*:}
2881 cntall="(select count($_i) from $_t where $_i=a.id)"
2882 # XXX: Dirty workaround for slow subquery of acclog
2883 presql="CREATE TEMPORARY TABLE IF NOT EXISTS myacclog AS
2884 SELECT * FROM acclog WHERE user='$user' and tbl='$2';"
2885 cntnew="(select count(val) from ${_t}_s where key='ctime' \
2886 and id in (select id from $_t where $_i=a.id) \
2887 and val > coalesce((select time from myacclog where \
2888 tblrowid=a.rowid),\
2889 '1970-01-01'))"
2890 cnt="$cntnew as '新着', $cntall as '総数',"
2891 dt_class=" td2r td3r dumpblogs"
2892 fi
2893 # Construct join expression
2894 eav="" scols=""
2895 pk=`gettblpkey $2`
2896 substr=${dumpcollen:+"substr(val, 0, $dumpcollen)"}
2897 substr=${substr:-val}
2898 for col in ${3:-`gettbl_s_cols $2`}; do
2899 case $col in
2900 gecos) scols="$scols${scols:+, }${col#}"
2901 continue ;; # built-in column name
2902 *:*) col=${col%:*} as=${col#*:} ;;
2903 *) as=${col} ;;
2904 esac
2905 eav=$eav${eav:+,}" max(case key when '$col' then $substr end) as $as"
2906 scols="$scols${scols:+, }b.$as"
2907 done
2908 #case author when '$user' then a.rowid else '---' end as ID,
2909 sql=${DT_SQL:-"select \
2910 a.rowid as LINK,\
2911 $cnt\
2912 $scols from $2 a left join\
2913 (select $pk,$eav,
2914 max(case key when 'owner'
2915 then (SELECT gecos FROM gecoses WHERE name=val) END) as gecos
2916 from ${2}_s c group by $pk) b on a.$pk=b.$pk $4;"}
2917 ## err dt:SQL="`echo \"$presql$sql\"|tr -d '\n'`"
2918 cat<<EOF | sed "s,\(<TR><TD>\)\([1-9][0-9]*\)\(#[0-9a-fxs]*\)*</TD>,\1$elink$dvlink</TD>,"
2919 <div> <!-- for folding by check button (s4-funcs.sh:dumptable()) -->
2920 <div class="dumptable">
2921 <table class="b$dt_class">
2922 `sq -header -cmd ".mode $1" $db "$presql$sql"`
2923 </table>
2924 </div> <!-- dumptable -->
2925 </div> <!-- for folding by check button (s4-funcs.sh:dumptable()) -->
2926 EOF
2929 par2table() (
2930 # copy current parameters of par into destination table
2931 # $1=definition-file
2932 # Using $user and $session
2933 # Return value:
2934 # 0: Stored successfully
2935 # 1: Insufficient fillings
2936 # 2: No permission to modify the record
2937 # 3: Invalid rowid
2938 # 4: SUCCESS to delete
2939 # 5: Stop deletion for lack of confirm check
2940 # 6: Password length too short
2941 # 7: Password mismatch
2942 # 8: Old password incorrect
2943 rowid=`getpar rowid`
2944 if [ ! -e $1 ]; then
2945 echo "テーブル定義ファイルが見付かりません" | html p
2946 exit 1
2947 fi
2948 tbl=${1%.def}
2949 tbl=${tbl##*/}
2950 if [ -n "$rowid" ]; then # Modify existing entry
2951 if [ x"$tbl" = x"user" ]; then
2952 rowowner=`query "select name from $tbl where rowid=$rowid;"`
2953 elif [ x"$tbl" = x"grp" ]; then
2954 sql="select gname from $tbl where rowid=$rowid;"
2955 ##err p2t:grp:q $sql
2956 isgrpowner $user "`query $sql`" && rowowner=$user
2957 else
2958 rowowner=`query "select owner from $tbl where rowid=$rowid;"`
2959 rowowner=${rowowner:-`query "select author from $tbl
2960 where rowid=$rowid;"`}
2961 fi
2962 ### err rowowner=$rowowner
2963 if [ x"$user" != x"$rowowner" ]; then
2964 echo "他人のレコードはいじれないの" | html p
2965 return 2
2966 elif [ -z "$rowowner" ]; then
2967 echo "指定したレコードはないみたい" | html p
2968 return 3
2969 fi
2970 rm=`getpar rm` cfm=`getpar confirm`
2971 # Editing existent entry
2972 if [ x"$rm" = x"yes" ]; then
2973 if [ x"$rm$cfm" = x"yesyes" ]; then
2974 query "delete from $tbl where rowid=$rowid;"
2975 return 4
2976 else
2977 echo "消去確認のチェックがないので消さなかったの..." | html p
2978 return 5
2979 fi
2980 fi
2981 fi
2983 ts=${tbl}_s tm=${tbl}_m val="" pval="" formaster=""
2984 if [ -n "$rowid" ]; then
2985 # Update of existing record
2986 for col in `gettblcols $tbl`; do
2987 val=`getparquote $col`
2988 [ -z "$val" ] && continue
2989 ## err query "update $tbl set $col=$val where rowid=$rowid"
2990 ## XX: THIS IS DIRTY hack to ensure non-foreign key in blog_s
2991 sql="update $tbl set $col=$val where rowid=$rowid;"
2992 if [ x"$tbl" = x"grp" -a x"$col" = x"gname" \
2993 -o x"tbl" = x"user" -a x"$col" = x"name" ]; then
2994 ## User name cannot be changed with interface provided with this
2995 ## script. But we offer the trigger to change owner user
2996 ## of blog_s table.
2997 #err "select quote($col) from $tbl where rowid=$rowid;"
2998 old=`query "select quote($col) from $tbl where rowid=$rowid;"`
2999 cat<<-EOF | query
3000 -- Here we cannot use BEGIN-COMMIT because groupupdate()
3001 -- should use EXCLUSIVE transaction outside of this.
3002 SAVEPOINT par2table;
3003 $sql
3004 update blog_s set val=$val
3005 where key='owner' and val=$old;
3006 RELEASE SAVEPOINT par2table;
3007 EOF
3008 ## XX: DIRTY Hack Ends here
3009 ## We should keep blog's owner as a single column which has
3010 ## foreign key constraint with primary key of grp/user.
3011 else
3012 query "$sql"
3013 fi
3014 done
3015 # Then, set up $pval for further insertion of tbl_s and tbl_m
3016 for col in `gettblpkey $tbl`; do
3017 val=`query "select $col from $tbl where rowid=$rowid;"|sed -e 's/\"/\"\"/g'`
3018 pval="$pval${pval:+, }\"$val\""
3019 done
3020 else
3021 # New entry
3022 # Generate values() for primary keys
3023 for col in `gettblpkey $tbl`; do
3024 # Genuine primary keys for _m and _s
3025 val=`getvalquote $tbl $col`
3026 [ -z "$val" ] && continue
3027 pval="$pval${pval:+, }$val"
3028 done
3029 ##err pval=$pval
3030 for col in `gettblfkey $tbl`; do
3031 # args for values() to insertion into master table
3032 val=`getvalquote $tbl $col`
3033 [ -z "$val" ] && continue
3034 formaster=$formaster"${formaster:+, }$val"
3035 done
3036 formaster="$pval${formaster:+, }$formaster"
3037 ## err formaster=$formaster
3038 if [ -z "$formaster" ]; then
3039 echo "項目を全て埋めてください" | html pre
3040 return 1
3041 fi
3042 ## err "replace into $tbl values($formaster);"
3043 query "replace into $tbl values($formaster);"
3044 ## Insertion to master table, done
3045 fi
3047 for kt in s m; do
3048 tb2=${tbl}_$kt
3049 for col in `gettbl_${kt}_cols $tbl`; do
3050 ptype=`getpartype $col "limit 1"`
3052 # First, check update of existing entries in _m
3053 if [ $kt = m ]; then
3054 # sessID|address.1.22|string|Somewhere-x.y.z
3055 sql=""
3056 ##err dots from query "select var from par where var like '$col.%';"
3057 for v in `query "select var from par where var like '$col.%';"`; do
3058 # v=address.1.22
3059 st_rowid=${v##*.}
3060 origcol=${v%%.*} # original column derived from
3061 ##err Updating for $v st_rowid=$st_rowid, partype=`getpartype $v`
3062 ##case `getpartype $v` in
3063 ## err CASE `gettbl_coltype $tbl/$origcol` in
3064 ## err edit flag = `getpar action.$v`
3065 case `getpar action.$v` in
3066 rm)
3067 if [ x`getpar confirm.$v` = x"yes" ]; then
3068 newsql="delete from $tb2"
3069 else
3070 echo "削除確認未チェック" | html p
3071 fi ;;
3072 edit)
3073 case `gettbl_coltype $tbl/$origcol` in
3074 image|document|binary)
3075 file=$tmpd/`getparfilename $v`
3076 ## err type=file=$file
3077 [ -z "$file" ] && continue
3078 bn=`sqlquotestr "${file##*/}"`
3079 bin="X'"$(hexize "$file")"'"
3080 ct=`file --mime-type - < "$file" |cut -d' ' -f2`
3081 type=\"file:$ct\"
3082 newsql="update $tb2 set val=$bn, type=$type, bin=$bin"
3083 cachedir=`getcachedir "$tbl/$rowid"`
3084 err getcache tbl/rowid=$tbl/$rowid, rm -r $cachedir
3085 rm -rf $cachedir
3086 ;;
3087 *)
3088 newsql="update $tb2 set val=(select val from par where var \
3089 like '$col.%.$st_rowid')"
3090 ;;
3091 esac
3092 ;;
3093 *) # maybe "keep", do not modify value
3094 continue
3095 ;;
3096 esac
3097 # err newsql=$newsql
3098 sql=$sql$nl"$newsql where rowid=$st_rowid;"
3099 done
3101 if [ x"$bin" = x"NULL" ]; then
3102 ## err repl:normal sql=`echo $sql`
3103 query "$sql
3104 delete from $tb2 where type='string' and val='';"
3105 ## err repl:normal done
3106 else
3107 sqlfile="$tmpd/sqlf.$$"
3108 echo "$sql" > $sqlfile
3109 ## err repl:sqlfile=`ls -lF $sqlfile`
3110 query ".read $sqlfile"
3111 ## err repl:done
3112 fi
3113 # Rest of kt==m: set multiple mode
3114 nr=`getparcount $col`
3115 else
3116 nr=1 # for kt==s, number of records is 1
3117 fi
3119 i=0
3120 while [ $i -lt $nr ]; do
3121 limit="limit 1 offset $i"
3122 i=$((i+1)) # increase beforehand against continue
3123 val=`getvalquote $tbl $col "$limit"`
3124 [ -z "$val" -o x"$val" = x'""' -o x"$val" = x"NULL" ] && continue
3125 ## err $col=$val
3126 bin=NULL
3127 ## err partype$col=`getpartype $col "$limit"`
3128 case $ptype in
3129 file) file=$tmpd/`getparfilename $col "$limit"`
3130 ## err parfile-$col=$file
3131 [ -z "$file" ] && continue
3132 bin="X'"$(hexize "$file")"'"
3133 ct=`file --mime-type - < "$file"|cut -d' ' -f2`
3134 type=\"file:$ct\" ;;
3135 "*"*) continue ;; # foreign table
3136 *) type=\"string\" ;;
3137 esac
3138 case `gettbl_coltype $tbl/$col` in
3139 password) # special care for password
3140 # name={password,pswd1,pswd2}
3141 p1=`getpar pswd1 "$limit"`
3142 if [ -z "$p1" ]; then
3143 continue # SKIP password setting, if p1 is empty
3144 else
3145 pswd=`getpar pswd "$limit"` p2=`getpar pswd2 "$limit"`
3146 ## err pswd=$pswd
3147 if pwcheck "$pswd"; then
3148 if [ x"$p1" = x"$p2" ]; then
3149 case "$p1" in
3150 ??????????*) ;;
3151 *) echo "パスワードは10字以上にしてください。" | html p
3152 return 6;;
3153 esac
3154 val="\"`echo $p1|mypwhash`\""
3155 else
3156 echo "2つの新パスワード不一致" | html p
3157 return 7
3158 fi
3159 else
3160 echo "旧パスワード違います" | html p
3161 return 8
3162 fi
3163 fi
3164 ;;
3165 esac
3166 ## err p2t: "replace into $tb2 values($pval, \"$col\", $type, $val, bin...);"
3167 #query "replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
3168 sql="replace into $tb2 values($pval, \"$col\", $type, $val, $bin);"
3169 if [ x"$bin" = x"NULL" ]; then
3170 ## err Normal-query: `echo $sql`
3171 query "$sql"
3172 else
3173 sqlfile="$tmpd/query.$$"
3174 echo "$sql" > $sqlfile
3175 ## err sqlfile=`ls -lF $sqlfile`
3176 query ".read $sqlfile"
3177 fi
3178 ## err p2t done
3179 done
3180 done
3181 done
3182 return 0
3183 ##err donee
3185 genform() {
3186 # $1 = form definition file
3187 # $2, $3 (optional)= table name and ROWID
3188 # If $GF_VIEWONLY set and nonNull, output values without form
3189 # If $GF_ARGS set, use it as content-strings in the form
3190 # If $GF_OWNER set, use it as value of name="owner"
3191 # If $GF_STAGE set, use it as value of name="stage"
3192 forms="" hiddens="" rowid=$3
3193 if [ ! -e "$1" ]; then
3194 echo "そのようなデータベースはないようです($2)。" | html p
3195 return
3196 elif [ -n "$2" ]; then
3197 rec=`query "select * from $2 where rowid='$rowid';"`
3198 if [ -z "$rec" ]; then
3199 pk=`gettblpkey $2`
3200 ###rec=`sq $db "select rowid from $2 where $pk='$rowid'"`
3201 rec=`query "select rowid from $2 where $pk='$rowid';"`
3202 rowid=$rec
3203 rec=$3
3204 fi
3205 if [ -z "$rec" ]; then
3206 echo "そんなレコードはないみたいね..." | html p
3207 return
3208 fi
3209 fi
3210 if [ -z "$GF_VIEWONLY" ]; then
3211 rm='<input id="rm" name="rm" type="checkbox"
3212 value="yes"><label for="rm">このエントリの削除</label>
3213 <span>ほんとうに消しますよ(確認)!
3214 <input name="confirm" type=checkbox value="yes">はい</span>'
3215 fi
3216 # Image Cache dir
3217 ## err genform: getcache=$2/$rowid
3218 td=`getcachedir "$2/$rowid"`
3219 while IFS=: read prompt name keytype type args; do
3220 [ -z "${prompt%%\#*}" ] && continue # skip comment line(#)
3221 sp="${args:+ }"
3222 form="" val=""
3223 if [ -n "$rowid" ]; then
3224 # err genform2a: Seeking for "$2.$name, type=$type"
3225 rawval=`getvalbyid $2 $name $rowid $td`
3226 val=`echo "$rawval"|htmlescape`
3227 ## err genform3a: getvalbyid $2 $name $rowid $td
3228 ## err genform3b: val="[$val]" type="$type"
3229 fi
3230 if [ -n "$GF_VIEWONLY" ]; then
3231 is_hidden "$2" "$name" && continue
3232 fi
3233 case "$type" in
3234 text*)
3235 cgiform=cgi_multi_$type
3236 if [ -s $td/$name.count -a -n "$val" ]; then
3237 form=`$cgiform $name $td`
3238 val=$(echo "$val"|
3239 while read fn; do
3240 echo "<tr><td>`cat $td/$fn|htmlescape|hreflink`
3241 </td></tr>$nl"
3242 done)
3243 val="<table>$nl$val$nl</table>"
3244 else
3245 #form="<input name=\"$name\" value=\"$val\" type=\"$type\"$sp$args>$nl"
3246 form=`cgi_$type $name "$rawval" "$args"`
3247 fi
3248 ;;
3249 [Rr][Aa][Dd][Ii][Oo])
3250 fh="<label><input type=\"radio\" name=\"$name\""
3251 form="`echo $args|sed -e \
3252 \"s,\([^ =][^=]*\)=\([^= ][^= ]*\),$fh value=\\"\2\\">\1</label>,g\"`"
3253 ;;
3254 [Cc][Hh][Ee][Cc][Kk][Bb][Oo][Xx])
3255 form="<label><input type=\"checkbox\" name=\"$name\" value=\"${args#*=}\">${args%=*}</label>"
3256 ;;
3257 [Ss][Ee][Ll][Ee][Cc][Tt])
3258 fh="<select name=\"$name\">$nl"
3259 form=$(for l in $args; do
3260 echo "<option value=\"${l#*=}\">${l%=*}</option>"
3261 done)
3262 if [ -n "$val" ]; then
3263 form=`echo $form|sed -e "s,\(value=.$val.\),\\1 selected,"`
3264 fi
3265 form="$fh$form</select>"
3266 ;;
3267 [Ii][Mm][Aa][Gg][Ee]|[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt]|[Bb]inary)
3268 if [ -s $td/$name.count ]; then
3269 form=`cgi_multi_file $name $td "$args"`
3270 if [ -n "$val" ]; then
3271 hrfb="$myname?showattc+$2_m"
3272 val=$(echo "$rawval" \
3273 | while read fn; do
3274 data=`percenthex "$td/$fn"`
3275 #ct=`cat $td/$fn.content-type`
3276 ct=`file --mime-type - < "$td/$fn"|cut -d' ' -f2`
3277 ri=`cat "$td/$fn.rowid"`
3278 ## err fn=$fn, name=$name, ri=$ri; ls -lF "$td/" 1>&3
3279 #imgsrc="<img src=\"data:$ct,$data\">"
3280 #echo "<a href=\"$hrfb+$ri\">$imgsrc</a><br>"
3281 iconhref "$td/$fn" "$hrfb+$ri" ""
3282 done)
3283 fi
3284 else
3285 form="<input type=\"file\" name=\"$name\" $args>"
3286 if [ -n "$val" ]; then
3287 imgs=$(echo "$rawval"\
3288 |while read fn;do
3289 data=`percenthex "$td/$fn"`
3290 echo "<img src=\"data:image/png,$data\">$fn<br>"
3291 done)
3292 form=$form"<br>$imgs"
3293 val=$imgs # 2015-06-15
3294 else
3295 form="<input type=\"file\" name=\"$name\" $args>"
3296 fi
3297 fi
3298 ;;
3299 [Hh][Ii][Dd][Dd][Ee][Nn])
3300 if [ -n "$GF_STAGE" -a x"$name" = x"stage" ]; then
3301 args="value=\"$GF_STAGE\""
3302 fi
3303 form="<input type=\"hidden\" name=\"$name\" $args>"
3304 prompt='' # Remove prompt
3305 ;;
3306 [Aa][Uu][Tt][Hh][Oo][Rr])
3307 form="<input type=\"hidden\" name=\"author\" value=\"$user\">"
3308 prompt="" ;;
3309 [Oo][Ww][Nn][Ee][Rr])
3310 val=${GF_OWNER:-$val}
3311 val=${val:-$user}
3312 form="<input type=\"hidden\" name=\"owner\" value=\"$val\">"
3313 prompt="" ;;
3314 [Uu][Ss][Ee][Rr])
3315 # XXX: is null $user ok?
3316 #form="<input type=\"hidden\" name=\"user\" value=\"$user\">"
3317 [ -n "$GF_VIEWONLY" ] && continue
3318 form="$user"
3319 ;;
3320 [Pp]assword)
3321 [ -n "$GF_VIEWONLY" ] && continue
3322 form="`cgi_passwd`"
3323 val=""
3324 ;;
3325 [Ss][Ee][Rr][Ii][Aa][Ll]|[Ss][Tt][Aa][Mm][Pp])
3326 if [ -z "$rowid" ]; then
3327 val=`genserial`
3328 fi
3329 form="<input type=\"hidden\" name=\"$name\" value=\"$val\">"
3330 prompt="" ;;
3331 [Ss][Ee][Ss][Ss][Ii][Oo][Nn])
3332 prompt=""
3333 ;;
3334 parent|path|blog*)
3335 prompt=""
3336 ;;
3337 "*"*)
3338 tail=$tail"``"
3339 continue ;;
3340 esac
3341 if [ -n "$prompt" ]; then
3342 if [ -n "${GF_VIEWONLY}" ]; then
3343 form=$val
3344 else
3346 fi
3347 forms=$forms" <tr class=\"$name\"><th>$prompt</th><td>$form</td></tr>$nl"
3348 else
3349 hiddens=$hiddens$nl"$form"
3350 fi
3351 done < $1
3352 # enctype="multipart/form-data"
3353 cat<<EOF
3354 <form action="${GF_ACTION:-$myname}" method="POST" enctype="multipart/form-data">
3355 ${rowid:+$rm}
3356 <table class="b $2">
3357 $forms
3358 </table>$hiddens
3359 ${GF_STAGE:+`cgi_hidden stage $GF_STAGE`}
3360 ${rowid:+<input type="hidden" name="rowid" value="$rowid">}
3361 EOF
3362 if [ -z $GF_VIEWONLY ]; then
3363 cat<<EOF
3364 <input type="submit" name="sub" value="OK">
3365 <input type="reset" name="res" value="Reset">
3366 EOF
3367 fi
3368 cat<<EOF
3369 $GF_ARGS</form>
3370 $tail
3371 EOF
3373 edittable() {
3374 # $1=form-def $2=table $3 rowid
3375 genform "$@"
3377 viewtable() {
3378 GF_VIEWONLY=1 genform "$@"
3380 showattc() {
3381 # $1=table_m $2=rowid &optional $3=RawFlag
3382 ## err \$1=$1 \$2=$2 \$3=$3
3383 if ! isfilereadable $user $1 $2; then
3384 contenttype; echo
3385 echo "このファイルは管理者のみしか見られません" | html p
3386 putfooter; exit
3387 fi
3388 idir=`umask 002; mktempd` || exit 1
3389 # tmpfiles=$tmpfiles"${tmpfiles+ }$idir"
3390 bin=$idir/$myname-$$.bin
3391 sql="select quote(bin) from $1 where rowid='$2';"
3392 ## err showattc: sql: $sql
3393 sq $db "$sql" | unhexize > $bin
3394 tv=`query "select type||'//'||val from $1 where rowid='$2';"`
3395 type=${tv%//*} fn=${tv#*//}
3396 ## err tv=$tv type=$type fn=$fn, tp2=${tv%\|*}
3397 ct=${type#file:}
3398 case $ct in # all text/* changed to text/plain
3399 text/*)
3400 charset=`nkf -g $bin|cut -d' ' -f1`
3401 case $charset in
3402 ASCII*) charset="" ;;
3403 esac
3404 if [ -z "$3" ]; then
3405 ct="text/html${charset:+; charset=$charset}"
3406 link="?showattc+$1+$2+raw"
3407 cat $bin | htmlescape \
3408 | sed 's,^,<span></span>,' \
3409 | _m4 -D_TITLE_="$fn" -D_CONTENT_TYPE_="$ct" \
3410 -D_LINK_="$link" \
3411 -D_BODY_="syscmd(\`cat')" $layout/pretty.m4.txt
3412 exit $?
3413 fi
3414 ct="text/plain${charset:+; charset=$charset}"
3415 ;;
3416 esac
3417 contenttype "$ct"
3418 echo "Content-Disposition: filename=\"$fn\""
3419 echo "Content-Length: " `cat $bin | wc -c`; echo
3420 #echo "Content-Type: " ${type#file:}; echo
3421 cat $bin
3424 # Some default stupid handler on CGI values
3426 default_storedb() {
3427 # ARG: $1=table-def-file
3428 # RET: $tbl=table-name, $col=mail-column, $cols=columns
3429 tbl=`basename $1`
3430 tbl=${tbl%.def}
3431 cols="`grep :text $1|cut -d: -f2`"
3432 col=`echo "$cols"|head -1`
3433 vcol=`getpar $col`
3434 err default0: \$1=$1 col=$col cols="[$cols]" vcol=$vcol
3435 if [ -n "$vcol" ]; then
3436 par2table $1
3437 else
3438 return 2 # No insertion occurred
3439 fi
3442 default_view() { # $1=def-file
3443 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
3444 ## DT_VIEW="edittable+$tbl" dumptable html $tbl "name memo file" \
3445 default_storedb "$@"
3446 query "select rowid from $tbl order by rowid desc;" \
3447 | while read rowid; do
3448 viewtable $1 $tbl $rowid
3449 done | _m4 -D_TITLE_="$tbl" \
3450 -D_FORM_="`genform $1`" \
3451 -D_DUMPTABLE_="syscmd(cat)" \
3452 $layout/html.m4.html $layout/form+dump.m4.html
3454 default_viewtext() { # $1=def-file
3455 ### DT_VIEW="edittable+$tbl" dumptable html $tbl "$cols" \
3456 default_storedb "$@"
3457 DT_VIEW="viewtable+$tbl" dumptable html $tbl "name memo file" \
3458 | _m4 -D_TITLE_="$tbl" \
3459 -D_FORM_="`genform $1`" \
3460 -D_DUMPTABLE_="syscmd(cat)" \
3461 $layout/html.m4.html $layout/form+dump.m4.html
3463 default_smail() {
3464 default_storedb "$@"
3465 if [ $? -eq 2 ]; then
3466 _m4 -D_TITLE_="入力" \
3467 -D_FORM_="`genform $1`" \
3468 -D_DUMPTABLE_="" \
3469 $layout/html.m4.html $layout/form+dump.m4.html
3470 return
3471 fi
3472 cond=""
3473 for pk in `gettblpkey $tbl`; do
3474 pv=$(sqlquote $(getpar $pk))
3475 cond="$cond${cond:+ and }$pk=$pv"
3476 done
3477 sql="select rowid from $tbl where $cond;"
3478 rowid=`query "$sql"`
3479 ## err smail1 - "$sql" "-> rowid=$rowid"
3481 while IFS=: read prompt name keytype type args; do # Read from $1
3482 val=`getpar $name`
3483 if [ -n "$val" ]; then
3484 text="$text
3485 $prompt
3486 $name=$val
3487 ---------------------------------------------------------"
3488 fi
3489 case "$type" in
3490 image|document|file)
3491 fn="`getvalbyid $tbl $name $rowid $tmpd`"
3492 fns=$(echo "$fn"|while read fn; do
3493 err mv $tmpd/$fn.orig $tmpd/$fn
3494 mv $tmpd/$fn.orig $tmpd/$fn
3495 rm $tmpd/$fn.rowid # Remove cache flag
3496 ## err "`ls $tmpd/$fn`"
3497 echo $fn
3498 done)
3499 files="$files $fns"
3500 ;;
3501 esac
3502 done < $1
3503 ## err FILES=$files "`ls -lF $tmpd`"
3504 subj="from ${REMOTE_ADDR}"
3505 (echo "$url"
3506 echo "への書き込みがありました。"
3507 echo "------"
3508 echo "$text"
3509 ) | (cd $tmpd &&
3510 err LS="`ls -lF`" &&
3511 $mydir/sendmultipart.sh -t "$admin" -s "$subj" $files)
3512 _m4 -D_TITLE_="入力完了" $layout/html.m4.html
3513 echo "以下の内容で送信しました。" | html p
3514 viewtable $1 $tbl \
3515 `query "select rowid from $tbl order by rowid desc limit 1;"`
3516 echo "戻る" | html a "href=\"?\""