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