core: Fix duplication of close_notify_handler for gpgsm.
[gpgme.git] / tests / run-encrypt.c
1 /* run-encrypt.c  - Helper to perform an encrypt operation
2  * Copyright (C) 2016 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <https://gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1-or-later
19  */
20
21 /* We need to include config.h so that we know whether we are building
22    with large file system (LFS) support. */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <gpgme.h>
32
33 #define PGM "run-encrypt"
34
35 #include "run-support.h"
36
37
38 static int verbose;
39
40
41 static char *
42 xstrdup (const char *string)
43 {
44   char *p = strdup (string);
45   if (!p)
46     {
47       fprintf (stderr, "strdup failed\n");
48       exit (2);
49     }
50   return p;
51 }
52
53
54 static gpg_error_t
55 status_cb (void *opaque, const char *keyword, const char *value)
56 {
57   (void)opaque;
58   fprintf (stderr, "status_cb: %s %s\n", nonnull(keyword), nonnull(value));
59   return 0;
60 }
61
62
63 static void
64 progress_cb (void *opaque, const char *what, int type, int current, int total)
65 {
66   (void)opaque;
67   (void)type;
68
69   if (total)
70     fprintf (stderr, "progress for '%s' %u%% (%d of %d)\n",
71              nonnull (what),
72              (unsigned)(((double)current / total) * 100), current, total);
73   else
74     fprintf (stderr, "progress for '%s' %d\n", nonnull(what), current);
75   fflush (stderr);
76 }
77
78
79 static void
80 print_result (gpgme_encrypt_result_t result)
81 {
82   gpgme_invalid_key_t invkey;
83
84   for (invkey = result->invalid_recipients; invkey; invkey = invkey->next)
85     printf ("Encryption key `%s' not used: %s <%s>\n",
86             nonnull (invkey->fpr),
87             gpg_strerror (invkey->reason), gpg_strsource (invkey->reason));
88 }
89
90
91
92 static int
93 show_usage (int ex)
94 {
95   fputs ("usage: " PGM " [options] FILE\n\n"
96          "Options:\n"
97          "  --verbose          run in verbose mode\n"
98          "  --status           print status lines from the backend\n"
99          "  --progress         print progress info\n"
100          "  --openpgp          use the OpenPGP protocol (default)\n"
101          "  --cms              use the CMS protocol\n"
102          "  --uiserver         use the UI server\n"
103          "  --loopback         use a loopback pinentry\n"
104          "  --key NAME         encrypt to key NAME\n"
105          "  --keystring NAMES  encrypt to ';' delimited NAMES\n"
106          "  --throw-keyids     use this option\n"
107          "  --no-symkey-cache  disable the use of that cache\n"
108          "  --wrap             assume input is valid OpenPGP message\n"
109          "  --symmetric        encrypt symmetric (OpenPGP only)\n"
110          , stderr);
111   exit (ex);
112 }
113
114
115 int
116 main (int argc, char **argv)
117 {
118   int last_argc = -1;
119   gpgme_error_t err;
120   gpgme_ctx_t ctx;
121   gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
122   gpgme_data_t in, out;
123   gpgme_encrypt_result_t result;
124   int print_status = 0;
125   int print_progress = 0;
126   int use_loopback = 0;
127   char *keyargs[10];
128   gpgme_key_t keys[10+1];
129   int keycount = 0;
130   char *keystring = NULL;
131   int i;
132   gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST;
133   gpgme_off_t offset;
134   int no_symkey_cache = 0;
135
136   if (argc)
137     { argc--; argv++; }
138
139   if (DIM(keys) != DIM(keyargs)+1)
140     abort ();
141
142   while (argc && last_argc != argc )
143     {
144       last_argc = argc;
145       if (!strcmp (*argv, "--"))
146         {
147           argc--; argv++;
148           break;
149         }
150       else if (!strcmp (*argv, "--help"))
151         show_usage (0);
152       else if (!strcmp (*argv, "--verbose"))
153         {
154           verbose = 1;
155           argc--; argv++;
156         }
157       else if (!strcmp (*argv, "--status"))
158         {
159           print_status = 1;
160           argc--; argv++;
161         }
162       else if (!strcmp (*argv, "--progress"))
163         {
164           print_progress = 1;
165           argc--; argv++;
166         }
167       else if (!strcmp (*argv, "--openpgp"))
168         {
169           protocol = GPGME_PROTOCOL_OpenPGP;
170           argc--; argv++;
171         }
172       else if (!strcmp (*argv, "--cms"))
173         {
174           protocol = GPGME_PROTOCOL_CMS;
175           argc--; argv++;
176         }
177       else if (!strcmp (*argv, "--uiserver"))
178         {
179           protocol = GPGME_PROTOCOL_UISERVER;
180           argc--; argv++;
181         }
182       else if (!strcmp (*argv, "--key"))
183         {
184           argc--; argv++;
185           if (!argc)
186             show_usage (1);
187           if (keycount == DIM (keyargs))
188             show_usage (1);
189           keyargs[keycount++] = *argv;
190           argc--; argv++;
191         }
192       else if (!strcmp (*argv, "--keystring"))
193         {
194           argc--; argv++;
195           if (!argc)
196             show_usage (1);
197           keystring = xstrdup (*argv);
198           for (i=0; keystring[i]; i++)
199             if (keystring[i] == ';')
200               keystring[i] = '\n';
201           argc--; argv++;
202         }
203       else if (!strcmp (*argv, "--throw-keyids"))
204         {
205           flags |= GPGME_ENCRYPT_THROW_KEYIDS;
206           argc--; argv++;
207         }
208       else if (!strcmp (*argv, "--wrap"))
209         {
210           flags |= GPGME_ENCRYPT_WRAP;
211           argc--; argv++;
212         }
213       else if (!strcmp (*argv, "--loopback"))
214         {
215           use_loopback = 1;
216           argc--; argv++;
217         }
218       else if (!strcmp (*argv, "--symmetric"))
219         {
220           flags |= GPGME_ENCRYPT_SYMMETRIC;
221           argc--; argv++;
222         }
223       else if (!strcmp (*argv, "--no-symkey-cache"))
224         {
225           no_symkey_cache = 1;
226           argc--; argv++;
227         }
228       else if (!strncmp (*argv, "--", 2))
229         show_usage (1);
230
231     }
232
233   if (argc != 1)
234     show_usage (1);
235
236   init_gpgme (protocol);
237
238   err = gpgme_new (&ctx);
239   fail_if_err (err);
240   gpgme_set_protocol (ctx, protocol);
241   gpgme_set_armor (ctx, 1);
242   if (print_status)
243     {
244       gpgme_set_status_cb (ctx, status_cb, NULL);
245       gpgme_set_ctx_flag (ctx, "full-status", "1");
246     }
247   if (print_progress)
248     gpgme_set_progress_cb (ctx, progress_cb, NULL);
249   if (use_loopback)
250     {
251       gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
252       gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
253     }
254   if (no_symkey_cache)
255     {
256       err = gpgme_set_ctx_flag (ctx, "no-symkey-cache", "1");
257       if (err)
258         {
259           fprintf (stderr, PGM ": error setting no-symkey-cache:  %s\n",
260                    gpgme_strerror (err));
261           exit (1);
262         }
263     }
264
265   for (i=0; i < keycount; i++)
266     {
267       err = gpgme_get_key (ctx, keyargs[i], &keys[i], 0);
268       fail_if_err (err);
269     }
270   keys[i] = NULL;
271
272   err = gpgme_data_new_from_file (&in, *argv, 1);
273   if (err)
274     {
275       fprintf (stderr, PGM ": error reading `%s': %s\n",
276                *argv, gpg_strerror (err));
277       exit (1);
278     }
279   offset = gpgme_data_seek (in, 0, SEEK_END);
280   if (offset == (gpgme_off_t)(-1))
281     {
282       err = gpg_error_from_syserror ();
283       fprintf (stderr, PGM ": error seeking `%s': %s\n",
284                *argv, gpg_strerror (err));
285       exit (1);
286     }
287   if (gpgme_data_seek (in, 0, SEEK_SET) == (gpgme_off_t)(-1))
288     {
289       err = gpg_error_from_syserror ();
290       fprintf (stderr, PGM ": error seeking `%s': %s\n",
291                *argv, gpg_strerror (err));
292       exit (1);
293     }
294   {
295     char numbuf[50];
296     char *p;
297
298     p = numbuf + sizeof numbuf;
299     *--p = 0;
300     do
301       {
302         *--p = '0' + (offset % 10);
303         offset /= 10;
304       }
305     while (offset);
306     err = gpgme_data_set_flag (in, "size-hint", p);
307     if (err)
308       {
309         fprintf (stderr, PGM ": error setting size-hint for `%s': %s\n",
310                  *argv, gpg_strerror (err));
311         exit (1);
312       }
313   }
314
315   err = gpgme_data_new (&out);
316   fail_if_err (err);
317
318   err = gpgme_op_encrypt_ext (ctx, keycount ? keys : NULL, keystring,
319                               flags, in, out);
320   result = gpgme_op_encrypt_result (ctx);
321   if (result)
322     print_result (result);
323   if (err)
324     {
325       fprintf (stderr, PGM ": encrypting failed: %s\n", gpg_strerror (err));
326       exit (1);
327     }
328
329   fputs ("Begin Output:\n", stdout);
330   print_data (out);
331   fputs ("End Output.\n", stdout);
332   gpgme_data_release (out);
333
334   gpgme_data_release (in);
335
336   for (i=0; i < keycount; i++)
337     gpgme_key_unref (keys[i]);
338   gpgme_release (ctx);
339   free (keystring);
340   return 0;
341 }