mutt stable branch with some hacks
1/*
2 * Copyright (C) 1997-2003 Thomas Roessler <roessler@does-not-exist.org>
3 *
4 * This program is free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22/* This file contains the new pgp invocation code. Note that this
23 * is almost entirely format based.
24 */
25
26#if HAVE_CONFIG_H
27# include "config.h"
28#endif
29
30#include <sys/types.h>
31#include <sys/stat.h>
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37#include <fcntl.h>
38#include <time.h>
39
40#include "mutt.h"
41#include "mutt_curses.h"
42#include "mutt_idna.h"
43#include "pgp.h"
44#include "rfc822.h"
45
46/*
47 * The actual command line formatter.
48 */
49
50struct pgp_command_context {
51 short need_passphrase; /* %p */
52 const char *fname; /* %f */
53 const char *sig_fname; /* %s */
54 const char *signas; /* %a */
55 const char *ids; /* %r */
56};
57
58
59const char *_mutt_fmt_pgp_command (char *dest,
60 size_t destlen,
61 size_t col,
62 int cols,
63 char op,
64 const char *src,
65 const char *prefix,
66 const char *ifstring,
67 const char *elsestring,
68 unsigned long data,
69 format_flag flags)
70{
71 char fmt[16];
72 struct pgp_command_context *cctx = (struct pgp_command_context *) data;
73 int optional = (flags & MUTT_FORMAT_OPTIONAL);
74
75 switch (op)
76 {
77 case 'r':
78 {
79 if (!optional)
80 {
81 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
82 snprintf (dest, destlen, fmt, NONULL (cctx->ids));
83 }
84 else if (!cctx->ids)
85 optional = 0;
86 break;
87 }
88
89 case 'a':
90 {
91 if (!optional)
92 {
93 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
94 snprintf (dest, destlen, fmt, NONULL (cctx->signas));
95 }
96 else if (!cctx->signas)
97 optional = 0;
98 break;
99 }
100
101 case 's':
102 {
103 if (!optional)
104 {
105 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
106 snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname));
107 }
108 else if (!cctx->sig_fname)
109 optional = 0;
110 break;
111 }
112
113 case 'f':
114 {
115 if (!optional)
116 {
117 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
118 snprintf (dest, destlen, fmt, NONULL (cctx->fname));
119 }
120 else if (!cctx->fname)
121 optional = 0;
122 break;
123 }
124
125 case 'p':
126 {
127 if (!optional)
128 {
129 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
130 snprintf (dest, destlen, fmt, cctx->need_passphrase ? "PGPPASSFD=0" : "");
131 }
132 else if (!cctx->need_passphrase || pgp_use_gpg_agent())
133 optional = 0;
134 break;
135 }
136 default:
137 {
138 *dest = '\0';
139 break;
140 }
141 }
142
143 if (optional)
144 mutt_FormatString (dest, destlen, col, cols, ifstring, _mutt_fmt_pgp_command, data, 0);
145 else if (flags & MUTT_FORMAT_OPTIONAL)
146 mutt_FormatString (dest, destlen, col, cols, elsestring, _mutt_fmt_pgp_command, data, 0);
147
148 return (src);
149}
150
151void mutt_pgp_command (char *d, size_t dlen, struct pgp_command_context *cctx, const char *fmt)
152{
153 mutt_FormatString (d, dlen, 0, MuttIndexWindow->cols, NONULL (fmt), _mutt_fmt_pgp_command, (unsigned long) cctx, 0);
154 dprint (2, (debugfile, "mutt_pgp_command: %s\n", d));
155}
156
157/*
158 * Glue.
159 */
160
161
162static pid_t pgp_invoke (FILE **pgpin, FILE **pgpout, FILE **pgperr,
163 int pgpinfd, int pgpoutfd, int pgperrfd,
164 short need_passphrase,
165 const char *fname,
166 const char *sig_fname,
167 const char *ids,
168 const char *format)
169{
170 struct pgp_command_context cctx;
171 char cmd[HUGE_STRING];
172
173 memset (&cctx, 0, sizeof (cctx));
174
175 if (!format || !*format)
176 return (pid_t) -1;
177
178 cctx.need_passphrase = need_passphrase;
179 cctx.fname = fname;
180 cctx.sig_fname = sig_fname;
181 if (PgpSignAs)
182 cctx.signas = PgpSignAs;
183 else
184 cctx.signas = PgpDefaultKey;
185 cctx.ids = ids;
186
187 mutt_pgp_command (cmd, sizeof (cmd), &cctx, format);
188
189 return mutt_create_filter_fd (cmd, pgpin, pgpout, pgperr,
190 pgpinfd, pgpoutfd, pgperrfd);
191}
192
193
194/*
195 * The exported interface.
196 *
197 * This is historic and may be removed at some point.
198 *
199 */
200
201pid_t pgp_invoke_decode (FILE **pgpin, FILE **pgpout, FILE **pgperr,
202 int pgpinfd, int pgpoutfd, int pgperrfd,
203 const char *fname, short need_passphrase)
204{
205 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
206 need_passphrase, fname, NULL, NULL,
207 PgpDecodeCommand);
208}
209
210pid_t pgp_invoke_verify (FILE **pgpin, FILE **pgpout, FILE **pgperr,
211 int pgpinfd, int pgpoutfd, int pgperrfd,
212 const char *fname, const char *sig_fname)
213{
214 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
215 0, fname, sig_fname, NULL, PgpVerifyCommand);
216}
217
218pid_t pgp_invoke_decrypt (FILE **pgpin, FILE **pgpout, FILE **pgperr,
219 int pgpinfd, int pgpoutfd, int pgperrfd,
220 const char *fname)
221{
222 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
223 1, fname, NULL, NULL, PgpDecryptCommand);
224}
225
226pid_t pgp_invoke_sign (FILE **pgpin, FILE **pgpout, FILE **pgperr,
227 int pgpinfd, int pgpoutfd, int pgperrfd,
228 const char *fname)
229{
230 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
231 1, fname, NULL, NULL, PgpSignCommand);
232}
233
234
235pid_t pgp_invoke_encrypt (FILE **pgpin, FILE **pgpout, FILE **pgperr,
236 int pgpinfd, int pgpoutfd, int pgperrfd,
237 const char *fname, const char *uids, int sign)
238{
239 if (sign)
240 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
241 1, fname, NULL, uids,
242 PgpEncryptSignCommand);
243 else
244 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
245 0, fname, NULL, uids,
246 PgpEncryptOnlyCommand);
247}
248
249pid_t pgp_invoke_traditional (FILE **pgpin, FILE **pgpout, FILE **pgperr,
250 int pgpinfd, int pgpoutfd, int pgperrfd,
251 const char *fname, const char *uids, int flags)
252{
253 if (flags & ENCRYPT)
254 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
255 flags & SIGN ? 1 : 0, fname, NULL, uids,
256 flags & SIGN ? PgpEncryptSignCommand : PgpEncryptOnlyCommand);
257 else
258 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
259 1, fname, NULL, NULL,
260 PgpClearSignCommand);
261}
262
263
264void pgp_invoke_import (const char *fname)
265{
266 BUFFER *fnamebuf = NULL;
267 char cmd[HUGE_STRING];
268 struct pgp_command_context cctx;
269
270 fnamebuf = mutt_buffer_pool_get ();
271
272 memset (&cctx, 0, sizeof (cctx));
273
274 mutt_buffer_quote_filename (fnamebuf, fname);
275 cctx.fname = mutt_b2s (fnamebuf);
276 if (PgpSignAs)
277 cctx.signas = PgpSignAs;
278 else
279 cctx.signas = PgpDefaultKey;
280
281 mutt_pgp_command (cmd, sizeof (cmd), &cctx, PgpImportCommand);
282 mutt_system (cmd);
283
284 mutt_buffer_pool_release (&fnamebuf);
285}
286
287void pgp_invoke_getkeys (ADDRESS *addr)
288{
289 BUFFER *buff = NULL;
290 char tmp[LONG_STRING];
291 char cmd[HUGE_STRING];
292 int devnull;
293
294 char *personal;
295
296 struct pgp_command_context cctx;
297
298 if (!PgpGetkeysCommand) return;
299
300 buff = mutt_buffer_pool_get ();
301 memset (&cctx, 0, sizeof (cctx));
302
303 personal = addr->personal;
304 addr->personal = NULL;
305
306 *tmp = '\0';
307 mutt_addrlist_to_local (addr);
308 rfc822_write_address_single (tmp, sizeof (tmp), addr, 0);
309 mutt_buffer_quote_filename (buff, tmp);
310
311 addr->personal = personal;
312
313 cctx.ids = mutt_b2s (buff);
314
315 mutt_pgp_command (cmd, sizeof (cmd), &cctx, PgpGetkeysCommand);
316
317 devnull = open ("/dev/null", O_RDWR);
318
319 if (!isendwin ()) mutt_message _("Fetching PGP key...");
320
321 mutt_system (cmd);
322
323 if (!isendwin ()) mutt_clear_error ();
324
325 close (devnull);
326
327 mutt_buffer_pool_release (&buff);
328}
329
330pid_t pgp_invoke_export (FILE **pgpin, FILE **pgpout, FILE **pgperr,
331 int pgpinfd, int pgpoutfd, int pgperrfd,
332 const char *uids)
333{
334 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
335 0, NULL, NULL, uids,
336 PgpExportCommand);
337}
338
339pid_t pgp_invoke_verify_key (FILE **pgpin, FILE **pgpout, FILE **pgperr,
340 int pgpinfd, int pgpoutfd, int pgperrfd,
341 const char *uids)
342{
343 return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
344 0, NULL, NULL, uids,
345 PgpVerifyKeyCommand);
346}
347
348pid_t pgp_invoke_list_keys (FILE **pgpin, FILE **pgpout, FILE **pgperr,
349 int pgpinfd, int pgpoutfd, int pgperrfd,
350 pgp_ring_t keyring, LIST *hints)
351{
352 BUFFER *uids;
353 BUFFER *quoted;
354 pid_t rc;
355
356 uids = mutt_buffer_pool_get ();
357 quoted = mutt_buffer_pool_get ();
358
359 for (; hints; hints = hints->next)
360 {
361 mutt_buffer_quote_filename (quoted, (char *) hints->data);
362 mutt_buffer_addstr (uids, mutt_b2s (quoted));
363 if (hints->next)
364 mutt_buffer_addch (uids, ' ');
365 }
366
367 rc = pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
368 0, NULL, NULL, mutt_b2s (uids),
369 keyring == PGP_SECRING ? PgpListSecringCommand :
370 PgpListPubringCommand);
371
372 mutt_buffer_pool_release (&uids);
373 mutt_buffer_pool_release ("ed);
374 return rc;
375}