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