notmuch-emacs-mua (4269B)
1 #!/usr/bin/env bash 2 # 3 # notmuch-emacs-mua - start composing a mail on the command line 4 # 5 # Copyright © 2014 Jani Nikula 6 # 7 # This program is free software: you can redistribute it and/or modify 8 # it under the terms of the GNU General Public License as published by 9 # the Free Software Foundation, either version 3 of the License, or 10 # (at your option) any later version. 11 # 12 # This program is distributed in the hope that it will be useful, 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # GNU General Public License for more details. 16 # 17 # You should have received a copy of the GNU General Public License 18 # along with this program. If not, see https://www.gnu.org/licenses/ . 19 # 20 # Authors: Jani Nikula <jani@nikula.org> 21 # 22 23 set -eu 24 25 # escape: "expand" '\' as '\\' and '"' as '\"' 26 # calling convention: escape -v var "$arg" (like in bash printf). 27 escape () 28 { 29 local __escape_arg__=${3//\\/\\\\} 30 printf -v $2 '%s' "${__escape_arg__//\"/\\\"}" 31 } 32 33 EMACS=${EMACS:-emacs} 34 EMACSCLIENT=${EMACSCLIENT:-emacsclient} 35 36 PRINT_ONLY= 37 NO_WINDOW= 38 USE_EMACSCLIENT= 39 AUTO_DAEMON= 40 CREATE_FRAME= 41 ELISP= 42 MAILTO= 43 HELLO= 44 45 # Short options compatible with mutt(1). 46 while getopts :s:c:b:i:h opt; do 47 # Handle errors and long options. 48 case "${opt}" in 49 :) 50 echo "$0: short option -${OPTARG} requires an argument." >&2 51 exit 1 52 ;; 53 \?) 54 opt=$1 55 if [ "${OPTARG}" != "-" ]; then 56 echo "$0: unknown short option -${OPTARG}." >&2 57 exit 1 58 fi 59 60 case "${opt}" in 61 # Long options with arguments. 62 --subject=*|--to=*|--cc=*|--bcc=*|--body=*) 63 OPTARG=${opt#--*=} 64 opt=${opt%%=*} 65 ;; 66 # Long options without arguments. 67 --help|--print|--no-window-system|--client|--auto-daemon|--create-frame|--hello) 68 ;; 69 *) 70 echo "$0: unknown long option ${opt}, or argument mismatch." >&2 71 exit 1 72 ;; 73 esac 74 # getopts does not do this for what it considers errors. 75 OPTIND=$((OPTIND + 1)) 76 ;; 77 esac 78 79 escape -v OPTARG "${OPTARG-none}" 80 81 case "${opt}" in 82 --help|h) 83 exec man notmuch-emacs-mua 84 ;; 85 --subject|s) 86 ELISP="${ELISP} (message-goto-subject) (insert \"${OPTARG}\")" 87 ;; 88 --to) 89 ELISP="${ELISP} (message-goto-to) (insert \"${OPTARG}, \")" 90 ;; 91 --cc|c) 92 ELISP="${ELISP} (message-goto-cc) (insert \"${OPTARG}, \")" 93 ;; 94 --bcc|b) 95 ELISP="${ELISP} (message-goto-bcc) (insert \"${OPTARG}, \")" 96 ;; 97 --body|i) 98 ELISP="${ELISP} (message-goto-body) (insert-file \"${OPTARG}\")" 99 ;; 100 --print) 101 PRINT_ONLY=1 102 ;; 103 --no-window-system) 104 NO_WINDOW="-nw" 105 ;; 106 --client) 107 USE_EMACSCLIENT="yes" 108 ;; 109 --auto-daemon) 110 AUTO_DAEMON="--alternate-editor=" 111 CREATE_FRAME="-c" 112 ;; 113 --create-frame) 114 CREATE_FRAME="-c" 115 ;; 116 --hello) 117 HELLO=1 118 ;; 119 *) 120 # We should never end up here. 121 echo "$0: internal error (option ${opt})." >&2 122 exit 1 123 ;; 124 esac 125 126 shift $((OPTIND - 1)) 127 OPTIND=1 128 done 129 130 # Positional parameters. 131 for arg; do 132 escape -v arg "${arg}" 133 case $arg in 134 mailto:*) 135 if [ -n "${MAILTO}" ]; then 136 echo "$0: more than one mailto: argument." >&2 137 exit 1 138 fi 139 MAILTO="${arg}" 140 ;; 141 *) 142 ELISP="${ELISP} (message-goto-to) (insert \"${arg}, \")" 143 ;; 144 esac 145 done 146 147 if [ -n "${MAILTO}" ]; then 148 if [ -n "${ELISP}" ]; then 149 echo "$0: mailto: is not compatible with other message parameters." >&2 150 exit 1 151 fi 152 ELISP="(browse-url-mail \"${MAILTO}\")" 153 elif [ -z "${ELISP}" -a -n "${HELLO}" ]; then 154 ELISP="(notmuch)" 155 else 156 ELISP="(notmuch-mua-new-mail) ${ELISP}" 157 fi 158 159 # Kill the terminal/frame if we're creating one. 160 if [ -z "$USE_EMACSCLIENT" -o -n "$CREATE_FRAME" -o -n "$NO_WINDOW" ]; then 161 ELISP="${ELISP} (message-add-action #'save-buffers-kill-terminal 'exit)" 162 fi 163 164 escape -v pwd "$PWD" 165 166 # The crux of it all: construct an elisp progn and eval it. 167 ELISP="(prog1 'done (require 'notmuch) (cd \"$pwd\") ${ELISP})" 168 169 if [ -n "$PRINT_ONLY" ]; then 170 echo ${ELISP} 171 exit 0 172 fi 173 174 if [ -n "$USE_EMACSCLIENT" ]; then 175 # Evaluate the progn. 176 exec ${EMACSCLIENT} ${NO_WINDOW} ${CREATE_FRAME} ${AUTO_DAEMON} --eval "${ELISP}" 177 else 178 exec ${EMACS} ${NO_WINDOW} --eval "${ELISP}" 179 fi