diff options
Diffstat (limited to 'bin/mail/comment.sh')
-rwxr-xr-x | bin/mail/comment.sh | 90 |
1 files changed, 72 insertions, 18 deletions
diff --git a/bin/mail/comment.sh b/bin/mail/comment.sh index 807bcb2..d096ee8 100755 --- a/bin/mail/comment.sh +++ b/bin/mail/comment.sh | |||
@@ -1,41 +1,95 @@ | |||
1 | #! /bin/bash | 1 | #! /bin/bash |
2 | 2 | ||
3 | # Save incoming mail as comment | ||
4 | # Usage: | ||
5 | # echo '|<PATH_TO_THIS_SCRIPT>' >>~/.forward | ||
6 | |||
7 | mailto=${mailto:-$(whoami)@${HOSTNAME:?HOSTNAME is not specified}} | ||
3 | output_dir=${output_dir:-/srv/http} | 8 | output_dir=${output_dir:-/srv/http} |
4 | 9 | ||
10 | # Check mail is for comment {{{ | ||
11 | |||
5 | # Restore mail into variable | 12 | # Restore mail into variable |
6 | MAIL="$(tr -d '\r')" | 13 | MAIL="$(tr -d '\r')" |
7 | headers="$(<<<"$MAIL" sed '/^$/ q')" | 14 | header="$(<<<"$MAIL" sed '/^$/ q')" |
8 | contents="$(<<<"$MAIL" sed -n '/^$/,$ p' | sed '1d')" | 15 | body="$(<<<"$MAIL" sed -n '/^$/,$ p' | sed '1d')" |
16 | |||
17 | # determine mail is for comment by pattern | ||
18 | pattern='^Subject: .*comment on (https?://)?([^/]+)?/([^ ]+)$' | ||
19 | <<<"$header" grep -E "$pattern" >/dev/null || exit 0 | ||
20 | |||
21 | # }}} | ||
22 | # Process header fields {{{ | ||
9 | 23 | ||
10 | # enable execute last command in pipe under current shell | 24 | # enable execute last command in pipe under current shell |
11 | shopt -s lastpipe; set +m; | 25 | shopt -s lastpipe; set +m; |
12 | 26 | ||
13 | # get route (target page of comment) and id | 27 | # save each field of header into variables |
14 | <<<"$MAIL" sed -En '/^To: comment+/ {s/^To: comment\+([^+]+)\+?(.*)@.*$/\1 \2/p; q}; /^$/q' \ | 28 | <<<"$header" grep '^[a-zA-Z]' \ |
15 | | read route id | 29 | | while read field value; do |
30 | declare field=$(<<<$field tr [:lower:] [:upper:] | tr '-' '_' | tr -d ':') | ||
31 | declare $field="${value}" | ||
32 | done | ||
33 | DATE=${DATE:+$(date --rfc-3339 seconds --date "$DATE")} | ||
16 | 34 | ||
17 | # sender want comment on some page, but find no route for this | 35 | # }}} |
18 | if [ $route = "" ]; then | 36 | # Get path of output file {{{ |
19 | echo 'rcpt "comment+<ROUTE>" not matched' >&2 | 37 | |
38 | path=$(<<<"$header" sed -En "\\|${pattern}| {s//\\3/p; q}") | ||
39 | |||
40 | # sender want comment on some page, but find no path for this | ||
41 | if [ $path = "" ]; then | ||
42 | echo 'Cannot get target of comment from mail' >&2 | ||
20 | exit 1 | 43 | exit 1 |
21 | fi | 44 | fi |
22 | 45 | ||
23 | output=$output_dir/${route#/}.comment | 46 | # get output path |
24 | exec 1>>$output | 47 | [[ "$path" =~ '/$' ]] && path+=index |
48 | path=${path#/} | ||
49 | path=${path/.html} | ||
50 | output=$output_dir/${path}.comment.html | ||
51 | |||
52 | # }}} | ||
53 | # Get comment from mail body {{{ | ||
25 | 54 | ||
26 | # check mail includes multiple part | 55 | # check mail includes multiple part |
27 | <<<"$headers" grep '^Content-Type:.*mixed' >/dev/null | 56 | if [[ "$CONTENT_TYPE" =~ mixed ]]; then |
28 | if [ $? -eq 0 ]; then | 57 | boundary="$(<<<"$CONTENT_TYPE" sed -En 's/^.*boundary="(.*)".*$/\1/p')" |
29 | boundary="$(<<<"$headers" sed -En 's/^Content-Type:.*boundary="(.*)".*$/\1/p')" | ||
30 | if [ $boundary = "" ]; then | 58 | if [ $boundary = "" ]; then |
31 | echo 'cannot get boundary from mail header' >&2 | 59 | echo 'cannot get boundary from mail header' >&2 |
32 | exit 1 | 60 | exit 1 |
33 | fi | 61 | fi |
34 | 62 | ||
35 | # print content of first mail part | 63 | # print content of first mail part |
36 | pattern="\\@^--${boundary}\$@" | 64 | boundaryPat="\\|^--${boundary}\$|" |
37 | <<<"$contents" sed -n "${pattern},${pattern} p" | sed -n "1,4d; ${pattern} q; p" | 65 | <<<"$body" sed -n "${boundaryPat},${boundaryPat} p" | sed -n "1,4d; ${boundaryPat} q; p" \ |
38 | else | 66 | | read body |
39 | # print content | ||
40 | <<<"$contents" sed '/^$/,$ p' | ||
41 | fi | 67 | fi |
68 | |||
69 | # }}} | ||
70 | # Write comment to output file {{{ | ||
71 | |||
72 | # add basic html layout for output file if necessary | ||
73 | if [ ! -f $output ] || ! xmllint --html --nofixup-base-uris $output &>/dev/null; then | ||
74 | echo -e '<ul>\n</ul>' >$output | ||
75 | fi | ||
76 | # get line of insert position by header field "In-Reply-To" | ||
77 | if [ -n "${IN_REPLY_TO}" ]; then | ||
78 | line=$(grep -n "^<!-- ${IN_REPLY_TO} -->$" $output | cut -d':' -f1) | ||
79 | fi | ||
80 | |||
81 | # insert comment into output file | ||
82 | <<-COMMENT sed -i "${line:-1}r /dev/stdin" $output | ||
83 | <li> | ||
84 | <time datetime="${DATE}">${DATE}</time> | ||
85 | <a href="mailto:${mailto}?subject=comment on ${path}&in-reply-to=${MESSAGE_ID}">[reply]</a> | ||
86 | |||
87 | $(<<<"${body}" markdown) | ||
88 | |||
89 | <ul> | ||
90 | <!-- ${MESSAGE_ID} --> | ||
91 | </ul> | ||
92 | </li> | ||
93 | COMMENT | ||
94 | |||
95 | # }}} | ||