Nico Golde:
[apps/madmutt.git] / pgpinvoke.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1997-2000 Thomas Roessler <roessler@does-not-exist.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 /* This file contains the new pgp invocation code.  Note that this
11  * is almost entirely format based.
12  */
13
14 #if HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <time.h>
27
28 #include "mutt.h"
29 #include "mutt_curses.h"
30 #include "mutt_idna.h"
31 #include "pgp.h"
32 #include "rfc822.h"
33
34 /*
35  * The actual command line formatter.
36  */
37
38 struct pgp_command_context {
39   short need_passphrase;        /* %p */
40   const char *fname;            /* %f */
41   const char *sig_fname;        /* %s */
42   const char *signas;           /* %a */
43   const char *ids;              /* %r */
44 };
45
46
47 const char *_mutt_fmt_pgp_command (char *dest,
48                                    size_t destlen,
49                                    char op,
50                                    const char *src,
51                                    const char *prefix,
52                                    const char *ifstring,
53                                    const char *elsestring,
54                                    unsigned long data, format_flag flags)
55 {
56   char fmt[16];
57   struct pgp_command_context *cctx = (struct pgp_command_context *) data;
58   int optional = (flags & M_FORMAT_OPTIONAL);
59
60   switch (op) {
61   case 'r':
62     {
63       if (!optional) {
64         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
65         snprintf (dest, destlen, fmt, NONULL (cctx->ids));
66       }
67       else if (!cctx->ids)
68         optional = 0;
69       break;
70     }
71
72   case 'a':
73     {
74       if (!optional) {
75         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
76         snprintf (dest, destlen, fmt, NONULL (cctx->signas));
77       }
78       else if (!cctx->signas)
79         optional = 0;
80       break;
81     }
82
83   case 's':
84     {
85       if (!optional) {
86         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
87         snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname));
88       }
89       else if (!cctx->sig_fname)
90         optional = 0;
91       break;
92     }
93
94   case 'f':
95     {
96       if (!optional) {
97         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
98         snprintf (dest, destlen, fmt, NONULL (cctx->fname));
99       }
100       else if (!cctx->fname)
101         optional = 0;
102       break;
103     }
104
105   case 'p':
106     {
107       if (!optional) {
108         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
109         snprintf (dest, destlen, fmt,
110                   cctx->need_passphrase ? "PGPPASSFD=0" : "");
111       }
112       else if (!cctx->need_passphrase || pgp_use_gpg_agent ())
113         optional = 0;
114       break;
115     }
116   default:
117     {
118       *dest = '\0';
119       break;
120     }
121   }
122
123   if (optional)
124     mutt_FormatString (dest, destlen, ifstring, _mutt_fmt_pgp_command, data,
125                        0);
126   else if (flags & M_FORMAT_OPTIONAL)
127     mutt_FormatString (dest, destlen, elsestring, _mutt_fmt_pgp_command, data,
128                        0);
129
130   return (src);
131 }
132
133 void mutt_pgp_command (char *d, size_t dlen, struct pgp_command_context *cctx,
134                        const char *fmt)
135 {
136   mutt_FormatString (d, dlen, NONULL (fmt), _mutt_fmt_pgp_command,
137                      (unsigned long) cctx, 0);
138   dprint (2, (debugfile, "mutt_pgp_command: %s\n", d));
139 }
140
141 /*
142  * Glue.
143  */
144
145
146 static pid_t pgp_invoke (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
147                          int pgpinfd, int pgpoutfd, int pgperrfd,
148                          short need_passphrase,
149                          const char *fname,
150                          const char *sig_fname,
151                          const char *signas,
152                          const char *ids, const char *format)
153 {
154   struct pgp_command_context cctx;
155   char cmd[HUGE_STRING];
156
157   memset (&cctx, 0, sizeof (cctx));
158
159   if (!format || !*format)
160     return (pid_t) - 1;
161
162   cctx.need_passphrase = need_passphrase;
163   cctx.fname = fname;
164   cctx.sig_fname = sig_fname;
165   cctx.signas = signas;
166   cctx.ids = ids;
167
168   mutt_pgp_command (cmd, sizeof (cmd), &cctx, format);
169
170   return mutt_create_filter_fd (cmd, pgpin, pgpout, pgperr,
171                                 pgpinfd, pgpoutfd, pgperrfd);
172 }
173
174
175 /*
176  * The exported interface.
177  * 
178  * This is historic and may be removed at some point.
179  *
180  */
181
182
183 pid_t pgp_invoke_decode (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
184                          int pgpinfd, int pgpoutfd, int pgperrfd,
185                          const char *fname, short need_passphrase)
186 {
187   return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
188                      need_passphrase, fname, NULL, NULL, NULL,
189                      PgpDecodeCommand);
190 }
191
192 pid_t pgp_invoke_verify (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
193                          int pgpinfd, int pgpoutfd, int pgperrfd,
194                          const char *fname, const char *sig_fname)
195 {
196   return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
197                      0, fname, sig_fname, NULL, NULL, PgpVerifyCommand);
198 }
199
200 pid_t pgp_invoke_decrypt (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
201                           int pgpinfd, int pgpoutfd, int pgperrfd,
202                           const char *fname)
203 {
204   return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
205                      1, fname, NULL, NULL, NULL, PgpDecryptCommand);
206 }
207
208 pid_t pgp_invoke_sign (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
209                        int pgpinfd, int pgpoutfd, int pgperrfd,
210                        const char *fname)
211 {
212   return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
213                      1, fname, NULL, PgpSignAs, NULL, PgpSignCommand);
214 }
215
216
217 pid_t pgp_invoke_encrypt (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
218                           int pgpinfd, int pgpoutfd, int pgperrfd,
219                           const char *fname, const char *uids, int sign)
220 {
221   if (sign)
222     return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
223                        1, fname, NULL, PgpSignAs, uids,
224                        PgpEncryptSignCommand);
225   else
226     return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
227                        0, fname, NULL, NULL, uids, PgpEncryptOnlyCommand);
228 }
229
230 pid_t pgp_invoke_traditional (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
231                               int pgpinfd, int pgpoutfd, int pgperrfd,
232                               const char *fname, const char *uids, int flags)
233 {
234   if (flags & ENCRYPT)
235     return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
236                        flags & SIGN ? 1 : 0, fname, NULL, PgpSignAs, uids,
237                        flags & SIGN ? PgpEncryptSignCommand :
238                        PgpEncryptOnlyCommand);
239   else
240     return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
241                        1, fname, NULL, PgpSignAs, NULL, PgpClearSignCommand);
242 }
243
244
245 void pgp_invoke_import (const char *fname)
246 {
247   char _fname[_POSIX_PATH_MAX + SHORT_STRING];
248   char cmd[HUGE_STRING];
249   struct pgp_command_context cctx;
250
251   memset (&cctx, 0, sizeof (cctx));
252
253   mutt_quote_filename (_fname, sizeof (_fname), fname);
254   cctx.fname = _fname;
255
256   mutt_pgp_command (cmd, sizeof (cmd), &cctx, PgpImportCommand);
257   mutt_system (cmd);
258 }
259
260 void pgp_invoke_getkeys (ADDRESS * addr)
261 {
262   char buff[LONG_STRING];
263   char tmp[LONG_STRING];
264   char cmd[HUGE_STRING];
265   int devnull;
266
267   char *personal;
268
269   struct pgp_command_context cctx;
270
271   if (!PgpGetkeysCommand)
272     return;
273
274   memset (&cctx, 0, sizeof (cctx));
275
276   personal = addr->personal;
277   addr->personal = NULL;
278
279   *tmp = '\0';
280   mutt_addrlist_to_local (addr);
281   rfc822_write_address_single (tmp, sizeof (tmp), addr, 0);
282   mutt_quote_filename (buff, sizeof (buff), tmp);
283
284   addr->personal = personal;
285
286   cctx.ids = buff;
287
288   mutt_pgp_command (cmd, sizeof (cmd), &cctx, PgpGetkeysCommand);
289
290   devnull = open ("/dev/null", O_RDWR);
291
292   if (!isendwin ())
293     mutt_message _("Fetching PGP key...");
294
295   mutt_system (cmd);
296
297   if (!isendwin ())
298     mutt_clear_error ();
299
300   close (devnull);
301 }
302
303 pid_t pgp_invoke_export (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
304                          int pgpinfd, int pgpoutfd, int pgperrfd,
305                          const char *uids)
306 {
307   return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
308                      0, NULL, NULL, NULL, uids, PgpExportCommand);
309 }
310
311 pid_t pgp_invoke_verify_key (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
312                              int pgpinfd, int pgpoutfd, int pgperrfd,
313                              const char *uids)
314 {
315   return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
316                      0, NULL, NULL, NULL, uids, PgpVerifyKeyCommand);
317 }
318
319 pid_t pgp_invoke_list_keys (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr,
320                             int pgpinfd, int pgpoutfd, int pgperrfd,
321                             pgp_ring_t keyring, LIST * hints)
322 {
323   char uids[HUGE_STRING];
324   char tmpuids[HUGE_STRING];
325   char quoted[HUGE_STRING];
326
327   *uids = '\0';
328
329   for (; hints; hints = hints->next) {
330     mutt_quote_filename (quoted, sizeof (quoted), (char *) hints->data);
331     snprintf (tmpuids, sizeof (tmpuids), "%s %s", uids, quoted);
332     strcpy (uids, tmpuids);     /* __STRCPY_CHECKED__ */
333   }
334
335   return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd,
336                      0, NULL, NULL, NULL, uids,
337                      keyring == PGP_SECRING ? PgpListSecringCommand :
338                      PgpListPubringCommand);
339 }