citadel

My dotfiles, scripts and nix configs
git clone git://jb55.com/citadel
Log | Files | Refs | README | LICENSE

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