Add gpgconf related dummy options default_pubkey_algo.
[gnupg.git] / g10 / cpr.c
blob1533ac6613ca4fb92bc566609705b097d57862ed
1 /* status.c - Status message and command-fd interface
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
3 * 2004, 2005, 2006 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <signal.h>
29 #include "gpg.h"
30 #include "util.h"
31 #include "status.h"
32 #include "ttyio.h"
33 #include "options.h"
34 #include "main.h"
35 #include "i18n.h"
36 #include "cipher.h" /* for progress functions */
38 #define CONTROL_D ('D' - 'A' + 1)
42 static FILE *statusfp;
45 static void
46 progress_cb (void *ctx, const char *what, int printchar,
47 int current, int total)
49 char buf[50];
51 (void)ctx;
53 if ( printchar == '\n' && !strcmp (what, "primegen") )
54 snprintf (buf, sizeof buf -1, "%.20s X 100 100", what );
55 else
56 snprintf (buf, sizeof buf -1, "%.20s %c %d %d",
57 what, printchar=='\n'?'X':printchar, current, total );
58 write_status_text (STATUS_PROGRESS, buf);
62 /* Return true if the status message NO may currently be issued. We
63 need this to avoid syncronisation problem while auto retrieving a
64 key. There it may happen that a status NODATA is issued for a non
65 available key and the user may falsely interpret this has a missing
66 signature. */
67 static int
68 status_currently_allowed (int no)
70 if (!glo_ctrl.in_auto_key_retrieve)
71 return 1; /* Yes. */
73 /* We allow some statis anyway, so that import statistics are
74 correct and to avoid problems if the retriebval subsystem will
75 prompt the user. */
76 switch (no)
78 case STATUS_GET_BOOL:
79 case STATUS_GET_LINE:
80 case STATUS_GET_HIDDEN:
81 case STATUS_GOT_IT:
82 case STATUS_IMPORTED:
83 case STATUS_IMPORT_OK:
84 case STATUS_IMPORT_CHECK:
85 case STATUS_IMPORT_RES:
86 return 1; /* Yes. */
87 default:
88 break;
90 return 0; /* No. */
94 void
95 set_status_fd ( int fd )
97 static int last_fd = -1;
99 if ( fd != -1 && last_fd == fd )
100 return;
102 if ( statusfp && statusfp != stdout && statusfp != stderr )
103 fclose (statusfp);
104 statusfp = NULL;
105 if ( fd == -1 )
106 return;
108 if( fd == 1 )
109 statusfp = stdout;
110 else if( fd == 2 )
111 statusfp = stderr;
112 else
113 statusfp = fdopen( fd, "w" );
114 if( !statusfp ) {
115 log_fatal("can't open fd %d for status output: %s\n",
116 fd, strerror(errno));
118 last_fd = fd;
120 gcry_set_progress_handler ( progress_cb, NULL );
124 is_status_enabled()
126 return !!statusfp;
129 void
130 write_status ( int no )
132 write_status_text( no, NULL );
135 void
136 write_status_text ( int no, const char *text)
138 if( !statusfp || !status_currently_allowed (no) )
139 return; /* Not enabled or allowed. */
141 fputs ( "[GNUPG:] ", statusfp );
142 fputs ( get_status_string (no), statusfp );
143 if( text ) {
144 putc ( ' ', statusfp );
145 for (; *text; text++) {
146 if (*text == '\n')
147 fputs ( "\\n", statusfp );
148 else if (*text == '\r')
149 fputs ( "\\r", statusfp );
150 else
151 putc ( *(const byte *)text, statusfp );
154 putc ('\n',statusfp);
155 if ( fflush (statusfp) && opt.exit_on_status_write_error )
156 g10_exit (0);
160 void
161 write_status_error (const char *where, int errcode)
163 if (!statusfp || !status_currently_allowed (STATUS_ERROR))
164 return; /* Not enabled or allowed. */
166 fprintf (statusfp, "[GNUPG:] %s %s %u\n",
167 get_status_string (STATUS_ERROR), where, gpg_err_code (errcode));
168 if (fflush (statusfp) && opt.exit_on_status_write_error)
169 g10_exit (0);
174 * Write a status line with a buffer using %XX escapes. If WRAP is >
175 * 0 wrap the line after this length. If STRING is not NULL it will
176 * be prepended to the buffer, no escaping is done for string.
177 * A wrap of -1 forces spaces not to be encoded as %20.
179 void
180 write_status_text_and_buffer ( int no, const char *string,
181 const char *buffer, size_t len, int wrap )
183 const char *s, *text;
184 int esc, first;
185 int lower_limit = ' ';
186 size_t n, count, dowrap;
188 if( !statusfp || !status_currently_allowed (no) )
189 return; /* Not enabled or allowed. */
191 if (wrap == -1) {
192 lower_limit--;
193 wrap = 0;
196 text = get_status_string (no);
197 count = dowrap = first = 1;
198 do {
199 if (dowrap) {
200 fprintf (statusfp, "[GNUPG:] %s ", text );
201 count = dowrap = 0;
202 if (first && string) {
203 fputs (string, statusfp);
204 count += strlen (string);
205 /* Make sure that there is space after the string. */
206 if (*string && string[strlen (string)-1] != ' ')
208 putc (' ', statusfp);
209 count++;
212 first = 0;
214 for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) {
215 if ( *s == '%' || *(const byte*)s <= lower_limit
216 || *(const byte*)s == 127 )
217 esc = 1;
218 if ( wrap && ++count > wrap ) {
219 dowrap=1;
220 break;
223 if (esc) {
224 s--; n++;
226 if (s != buffer)
227 fwrite (buffer, s-buffer, 1, statusfp );
228 if ( esc ) {
229 fprintf (statusfp, "%%%02X", *(const byte*)s );
230 s++; n--;
232 buffer = s;
233 len = n;
234 if ( dowrap && len )
235 putc ( '\n', statusfp );
236 } while ( len );
238 putc ('\n',statusfp);
239 if ( fflush (statusfp) && opt.exit_on_status_write_error )
240 g10_exit (0);
243 void
244 write_status_buffer ( int no, const char *buffer, size_t len, int wrap )
246 write_status_text_and_buffer (no, NULL, buffer, len, wrap);
250 /* Print the BEGIN_SIGNING status message. If MD is not NULL it is
251 used to retrieve the hash algorithms used for the message. */
252 void
253 write_status_begin_signing (gcry_md_hd_t md)
255 if (md)
257 char buf[100];
258 size_t buflen;
259 int i;
261 /* We use a hard coded list of possible algorithms. Using other
262 algorithms than specified by OpenPGP does not make sense
263 anyway. We do this out of performance reasons: Walking all
264 the 110 allowed Ids is not a good idea given the way the
265 check is implemented in libgcrypt. Recall that the only use
266 of this status code is to create the micalg algorithm for
267 PGP/MIME. */
268 buflen = 0;
269 for (i=1; i <= 11; i++)
270 if (i < 4 || i > 7)
271 if ( gcry_md_is_enabled (md, i) && buflen < DIM(buf) )
273 snprintf (buf+buflen, DIM(buf) - buflen - 1,
274 "%sH%d", buflen? " ":"",i);
275 buflen += strlen (buf+buflen);
277 write_status_text ( STATUS_BEGIN_SIGNING, buf );
279 else
280 write_status ( STATUS_BEGIN_SIGNING );
284 static int
285 myread(int fd, void *buf, size_t count)
287 int rc;
288 do {
289 rc = read( fd, buf, count );
290 } while ( rc == -1 && errno == EINTR );
291 if ( !rc && count ) {
292 static int eof_emmited=0;
293 if ( eof_emmited < 3 ) {
294 *(char*)buf = CONTROL_D;
295 rc = 1;
296 eof_emmited++;
298 else { /* Ctrl-D not caught - do something reasonable */
299 #ifdef HAVE_DOSISH_SYSTEM
300 raise (SIGINT); /* nothing to hangup under DOS */
301 #else
302 raise (SIGHUP); /* no more input data */
303 #endif
306 return rc;
311 /* Request a string from the client over the command-fd. If GETBOOL
312 is set the function returns a static string (do not free) if the
313 netered value was true or NULL if the entered value was false. */
314 static char *
315 do_get_from_fd ( const char *keyword, int hidden, int getbool )
317 int i, len;
318 char *string;
320 if (statusfp != stdout)
321 fflush (stdout);
323 write_status_text (getbool? STATUS_GET_BOOL :
324 hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword);
326 for (string = NULL, i = len = 200; ; i++ )
328 if (i >= len-1 )
330 char *save = string;
331 len += 100;
332 string = hidden? xmalloc_secure ( len ) : xmalloc ( len );
333 if (save)
334 memcpy (string, save, i );
335 else
336 i = 0;
338 /* Fixme: why not use our read_line function here? */
339 if ( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n' )
340 break;
341 else if ( string[i] == CONTROL_D )
343 /* Found ETX - Cancel the line and return a sole ETX. */
344 string[0] = CONTROL_D;
345 i = 1;
346 break;
349 string[i] = 0;
351 write_status (STATUS_GOT_IT);
353 if (getbool) /* Fixme: is this correct??? */
354 return (string[0] == 'Y' || string[0] == 'y') ? "" : NULL;
356 return string;
362 cpr_enabled()
364 if( opt.command_fd != -1 )
365 return 1;
366 return 0;
369 char *
370 cpr_get_no_help( const char *keyword, const char *prompt )
372 char *p;
374 if( opt.command_fd != -1 )
375 return do_get_from_fd ( keyword, 0, 0 );
376 for(;;) {
377 p = tty_get( prompt );
378 return p;
382 char *
383 cpr_get( const char *keyword, const char *prompt )
385 char *p;
387 if( opt.command_fd != -1 )
388 return do_get_from_fd ( keyword, 0, 0 );
389 for(;;) {
390 p = tty_get( prompt );
391 if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
392 xfree(p);
393 display_online_help( keyword );
395 else
396 return p;
401 char *
402 cpr_get_utf8( const char *keyword, const char *prompt )
404 char *p;
405 p = cpr_get( keyword, prompt );
406 if( p ) {
407 char *utf8 = native_to_utf8( p );
408 xfree( p );
409 p = utf8;
411 return p;
414 char *
415 cpr_get_hidden( const char *keyword, const char *prompt )
417 char *p;
419 if( opt.command_fd != -1 )
420 return do_get_from_fd ( keyword, 1, 0 );
421 for(;;) {
422 p = tty_get_hidden( prompt );
423 if( *p == '?' && !p[1] ) {
424 xfree(p);
425 display_online_help( keyword );
427 else
428 return p;
432 void
433 cpr_kill_prompt(void)
435 if( opt.command_fd != -1 )
436 return;
437 tty_kill_prompt();
438 return;
442 cpr_get_answer_is_yes( const char *keyword, const char *prompt )
444 int yes;
445 char *p;
447 if( opt.command_fd != -1 )
448 return !!do_get_from_fd ( keyword, 0, 1 );
449 for(;;) {
450 p = tty_get( prompt );
451 trim_spaces(p); /* it is okay to do this here */
452 if( *p == '?' && !p[1] ) {
453 xfree(p);
454 display_online_help( keyword );
456 else {
457 tty_kill_prompt();
458 yes = answer_is_yes(p);
459 xfree(p);
460 return yes;
466 cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
468 int yes;
469 char *p;
471 if( opt.command_fd != -1 )
472 return !!do_get_from_fd ( keyword, 0, 1 );
473 for(;;) {
474 p = tty_get( prompt );
475 trim_spaces(p); /* it is okay to do this here */
476 if( *p == '?' && !p[1] ) {
477 xfree(p);
478 display_online_help( keyword );
480 else {
481 tty_kill_prompt();
482 yes = answer_is_yes_no_quit(p);
483 xfree(p);
484 return yes;
491 cpr_get_answer_okay_cancel (const char *keyword,
492 const char *prompt,
493 int def_answer)
495 int yes;
496 char *answer = NULL;
497 char *p;
499 if( opt.command_fd != -1 )
500 answer = do_get_from_fd ( keyword, 0, 0 );
502 if (answer)
504 yes = answer_is_okay_cancel (answer, def_answer);
505 xfree (answer);
506 return yes;
509 for(;;)
511 p = tty_get( prompt );
512 trim_spaces(p); /* it is okay to do this here */
513 if (*p == '?' && !p[1])
515 xfree(p);
516 display_online_help (keyword);
518 else
520 tty_kill_prompt();
521 yes = answer_is_okay_cancel (p, def_answer);
522 xfree(p);
523 return yes;