diff options
Diffstat (limited to 'bin')
| -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 | # }}} | ||