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