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