]> git.cworth.org Git - notmuch-wiki/blob - remoteusage/124.mdwn
fix link
[notmuch-wiki] / remoteusage / 124.mdwn
1 ## Remoteusage without password-free login requirement
2
3 This is alternative to [[remoteusage|remoteusage]] where password-free
4 login is not a requirement. See [[remoteusage|remoteusage]] page for
5 other requirements and general information.
6
7 This solution uses one pre-made ssh connection where the client is put
8 into "master" mode (-M) for connection sharing. The wrapper script then
9 uses the control socket created by this pre-made ssh connection for
10 its own connection. As long as master ssh connection is live, slave
11 can use it. Disconnecting master all future attempts to connect
12 from the script will fail.
13
14 It is possible to use this solution without any changes to
15 `$HOME/.ssh/config`.
16
17 At the end of this document there is information for some possible ways
18 how master ssh connection can be done.
19
20 ## The script
21
22 Write the following code to a file, for example `remote-notmuch.sh`.
23
24         #!/bin/bash
25
26         set -euf
27
28         # To trace execution, uncomment next line:
29         #exec 6>>remote-errors; BASH_XTRACEFD=6; echo -- >&6; set -x
30
31         : ${REMOTE_NOTMUCH_SSHCTRL_SOCK:=master-notmuch@remote:22}
32         : ${REMOTE_NOTMUCH_COMMAND:=notmuch}
33
34         readonly REMOTE_NOTMUCH_SSHCTRL_SOCK REMOTE_NOTMUCH_COMMAND
35
36         SSH_CONTROL_ARGS='-oControlMaster=no -S ~'/.ssh/$REMOTE_NOTMUCH_SSHCTRL_SOCK
37         readonly SSH_CONTROL_ARGS
38
39         printf -v ARGS '%q ' "$@" # bash feature
40         readonly ARGS
41
42         if ssh -q $SSH_CONTROL_ARGS 0.1 "$REMOTE_NOTMUCH_COMMAND" $ARGS
43         then exit 0
44         else ev=$?
45         fi
46
47         # continuing here in case ssh exited with nonzero value
48
49         case $* in
50          'config get user.primary_email') echo 'nobody@nowhere.invalid'; exit 0 ;;
51          'config get user.name') echo 'nobody'; exit 0 ;;
52          'count'*'--batch'*) while read line; do echo 1; done; exit 0 ;;
53          'count'*) echo 1; exit 0 ;;
54          'search-tags'*) echo 'errors'; exit 0 ;;
55          'search'*'--output=tags'*) echo 'errors'; exit 0 ;;
56         esac
57
58         # fallback exit handler; print only to stderr...
59         exec >&2
60
61         if ssh $SSH_CONTROL_ARGS -O check 0.1
62         then
63          echo " Control socket is alive but something exited with status $ev"
64          exit $ev
65         fi
66
67         echo " See`sed '1d;2d;s/.//;q' "$0"` for help"
68         exit $ev
69         #eof
70
71 Note the `0.1` in ssh command line. It is used to avoid any opportunistic
72 behaviour ssh might do; for example if control socket is not alive ssh
73 would attempt to do its own ssh connection to remote ssh server. As
74 address `0.1` is invalid this attempt will fail early.
75
76 ## Test
77
78 Easiest way to test this script is to run the pre-made ssh connection
79 using the following command line:
80
81         ssh -M -S '~'/.ssh/master-notmuch@remote:22 [user@]remotehost sleep 600
82
83 (replace `[user@]remotehost` with your login info). Doing this the
84 above wrapper script can be run unmodified. After the above command has
85 been run on **one terminal**, enter `chmod +x remote-notmuch.sh` in
86 **another terminal** and then test the script with
87
88         ./remote-notmuch.sh help
89
90 Note that the '~' in the ssh command line above is inside single quotes
91 for a reason. In this case shell never expand it to `$HOME` -- ssh does
92 it by not reading `$HOME` but checking the real user home directory
93 from `/etc/passwd`.  For security purposes this is just how it should
94 be.
95
96 ## Tune
97
98 The path `'~'/.ssh/master-notmuch@remote:22` might look too generic to be
99 used as is as the control socket after initial testing (but it can
100 be used). It is presented as a template for what could be configured
101 to `$HOME/.ssh/config`. For example:
102
103         Host *
104             ControlPath ~/.ssh/master-%h@%p:%r
105
106 is a good entry to be written in `$HOME/.ssh/config`;
107 [[remoteusage|remoteusage]] uses the same. Now, let's say you'd
108 make your pre-made ssh connection with command
109
110         ssh -M robin@example.org
111
112 There are 3 options how to handle this with `./nottoomuch-remote.bash`:
113
114 1) Edit `./nottoomuch-remote.bash` and change `REMOTE_NOTMUCH_SSHCTRL_SOCK`
115    to contain the new value (being *master-robin@example.org:22* in this
116    case)
117
118 2) Make symlink:
119    `ln -sfT master-robin@example.org:22 ~/.ssh/master-notmuch@remote:22`
120
121 3) `REMOTE_NOTMUCH_SSHCTRL_SOCK` can be used via environment; like:
122
123       REMOTE_NOTMUCH_SSHCTRL_SOCK=master-robin@example.org:22 ./nottoomuch-remote.bash help
124
125 ## Configure Emacs on the client computer ##
126
127 Add something like the following functions to your Emacs (general(*) or
128 notmuch specific) configuration files:
129
130     ;; this should work as backend function when copied verbatim
131     (defun user/notmuch-remote-setup (sockname)
132       (setq notmuch-command "/path/to/nottoomuch-remote.bash")
133       (setenv "REMOTE_NOTMUCH_SSHCTRL_SOCK" sockname)
134       ;; If you use Fcc, you may want to do something like this on the client,
135       ;; to Bcc mails to yourself (if not, remove in your implementation):
136       (setq notmuch-fcc-dirs nil)
137       (add-hook 'message-header-setup-hook
138                 (lambda () (insert (format "Bcc: %s <%s>\n"
139                                            (notmuch-user-name)
140                                            (notmuch-user-primary-email))))))
141
142      ;; this is just an example to configure using "default" master socket
143      (defun user/notmuch-remote-default ()
144        (interactive)
145        (user/notmuch-remote-setup "master-notmuch@remote:22")
146
147      ;; usage example2: set USER & HOST1 according to your remote...
148      (defun user/notmuch-remote-at-HOST1 ()
149        (interactive)
150        (user/notmuch-remote-setup "master-USER@HOST1:22")
151
152      ;; ... you probably got the point now -- add relevant funcs to your config
153      (defun user/notmuch-remote-at-HOST2 ()
154        (interactive)
155        (user/notmuch-remote-setup "master-USER@HOST2:22")
156
157 ... and if you want to activate your remote by default just call
158 `(user/notmuch-remote-setup "master-USER@HOST:22")` without function call
159 wrapper.
160
161 (*) general most likely being ~/.emacs
162
163 ### Yet another possibility -- script to start emacs
164
165 Instead of adding new configurations you could also write a special
166 script which starts and configures emacs suitable for remote usage.
167 Copy the following "template" to a new name e.g. in `$HOME/bin/`,
168 edit the value for `master-USER@HOST3:22` and perhaps add more
169 post eval-after-load notmuch configs there.
170
171     #!/bin/sh
172     :; exec "${EMACS:-emacs}" --debug-init --load "$0" "$@"; exit
173
174     (setenv "REMOTE_NOTMUCH_SSHCTRL_SOCK" "master-USER@HOST3:22")
175
176     (eval-after-load "notmuch"
177       (lambda ()
178         (setq notmuch-command (concat (file-name-directory load-file-name)
179                                       "remote-notmuch.sh"))
180         ;; place for more post-notmuch-load emacs configs if any
181         ))
182     (notmuch)
183
184     ;; Local Variables:
185     ;; mode: emacs-lisp
186     ;; End:
187
188 ## Creating master connection
189
190 **(Note: all the examples below use the default master socket written in**
191 `./nottoomuch-remote.bash` **for initial test easiness; remove/change the**
192 `-S '~'/.ssh/master-notmuch@remote:22` **in case you don't need it.)**
193
194 As mentioned so many times, using this solution requires one pre-made
195 ssh connection in "master" mode. The simplest way is to dedicate one
196 terminal for the connection with shell access to the remote machine:
197
198         ssh -M -S '~'/.ssh/master-notmuch@remote:22 [user@]remotehost
199
200 One possibility is to have this dedicated terminal in a way that the
201 connection has (for example 1 hour) timeout:
202
203         ssh -M -S '~'/.ssh/master-notmuch@remote:22 [user@]remotehost sleep 3600
204
205 The above holds the terminal. The next alternative puts the command in
206 background:
207
208         ssh -f -M -S '~'/.ssh/master-notmuch@remote:22 [user@]remotehost sleep 3600
209
210 If you don't want this to timeout so soon, use a longer sleep, like 99999999
211 (8 9:s, 1157 days, a bit more than 3 years).
212
213 A more "exotic" solution would be to make a shell script running on remote
214 machine, checking/inotifying when new mail arrives. When mail arrives it
215 could send message back to local host, where a graphical client (to be written)
216 pops up on display providing info about received mail (and exiting this
217 graphical client connection to remote host is terminated).
218
219 ## Troubleshooting
220
221 If you experience strange output when using from emacs first attempt to just
222 run
223
224         ./remote-notmuch.sh help
225
226 from command line and observe output. If it looks as it should be next uncomment
227 the line
228
229         #exec 6>>remote-errors; BASH_XTRACEFD=6; echo -- >&6; set -x
230
231 in `./remote-notmuch.sh` and attempt to use it from emacs again -- and then
232 examine the contents of `remote-errors` in the working directory emacs was
233 started.