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/>.
36
#include "cipher.h" /* for progress functions */
38
#define CONTROL_D ('D' - 'A' + 1)
42
static FILE *statusfp;
46
progress_cb (void *ctx, const char *what, int printchar,
47
int current, int total)
51
if ( printchar == '\n' && !strcmp (what, "primegen") )
52
snprintf (buf, sizeof buf -1, "%.20s X 100 100", what );
54
snprintf (buf, sizeof buf -1, "%.20s %c %d %d",
55
what, printchar=='\n'?'X':printchar, current, total );
56
write_status_text (STATUS_PROGRESS, buf);
60
/* Return true if the status message NO may currently be issued. We
61
need this to avoid syncronisation problem while auto retrieving a
62
key. There it may happen that a status NODATA is issued for a non
63
available key and the user may falsely interpret this has a missing
66
status_currently_allowed (int no)
68
if (!glo_ctrl.in_auto_key_retrieve)
71
/* We allow some statis anyway, so that import statistics are
72
correct and to avoid problems if the retriebval subsystem will
78
case STATUS_GET_HIDDEN:
81
case STATUS_IMPORT_OK:
82
case STATUS_IMPORT_CHECK:
83
case STATUS_IMPORT_RES:
93
set_status_fd ( int fd )
95
static int last_fd = -1;
97
if ( fd != -1 && last_fd == fd )
100
if ( statusfp && statusfp != stdout && statusfp != stderr )
111
statusfp = fdopen( fd, "w" );
113
log_fatal("can't open fd %d for status output: %s\n",
114
fd, strerror(errno));
118
gcry_set_progress_handler ( progress_cb, NULL );
128
write_status ( int no )
130
write_status_text( no, NULL );
134
write_status_text ( int no, const char *text)
136
if( !statusfp || !status_currently_allowed (no) )
137
return; /* Not enabled or allowed. */
139
fputs ( "[GNUPG:] ", statusfp );
140
fputs ( get_status_string (no), statusfp );
142
putc ( ' ', statusfp );
143
for (; *text; text++) {
145
fputs ( "\\n", statusfp );
146
else if (*text == '\r')
147
fputs ( "\\r", statusfp );
149
putc ( *(const byte *)text, statusfp );
152
putc ('\n',statusfp);
153
if ( fflush (statusfp) && opt.exit_on_status_write_error )
159
* Write a status line with a buffer using %XX escapes. If WRAP is >
160
* 0 wrap the line after this length. If STRING is not NULL it will
161
* be prepended to the buffer, no escaping is done for string.
162
* A wrap of -1 forces spaces not to be encoded as %20.
165
write_status_text_and_buffer ( int no, const char *string,
166
const char *buffer, size_t len, int wrap )
168
const char *s, *text;
170
int lower_limit = ' ';
171
size_t n, count, dowrap;
173
if( !statusfp || !status_currently_allowed (no) )
174
return; /* Not enabled or allowed. */
181
text = get_status_string (no);
182
count = dowrap = first = 1;
185
fprintf (statusfp, "[GNUPG:] %s ", text );
187
if (first && string) {
188
fputs (string, statusfp);
189
count += strlen (string);
193
for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) {
194
if ( *s == '%' || *(const byte*)s <= lower_limit
195
|| *(const byte*)s == 127 )
197
if ( wrap && ++count > wrap ) {
206
fwrite (buffer, s-buffer, 1, statusfp );
208
fprintf (statusfp, "%%%02X", *(const byte*)s );
214
putc ( '\n', statusfp );
217
putc ('\n',statusfp);
218
if ( fflush (statusfp) && opt.exit_on_status_write_error )
223
write_status_buffer ( int no, const char *buffer, size_t len, int wrap )
225
write_status_text_and_buffer (no, NULL, buffer, len, wrap);
229
/* Print the BEGIN_SIGNING status message. If MD is not NULL it is
230
used retrieve the hash algorithms used for the message. */
232
write_status_begin_signing (gcry_md_hd_t md)
240
/* We use a hard coded list of possible algorithms. Using other
241
algorithms than specified by OpenPGP does not make sense
242
anyway. We do this out of performance reasons: Walking all
243
the 110 allowed Ids is not a good idea given the way the
244
check is implemented in libgcrypt. Recall that the only use
245
of this status code is to create the micalg algorithm for
248
for (i=1; i <= 11; i++)
250
if ( gcry_md_is_enabled (md, i) && buflen < DIM(buf) )
252
snprintf (buf+buflen, DIM(buf) - buflen - 1,
253
"%sH%d", buflen? " ":"",i);
254
buflen += strlen (buf+buflen);
256
write_status_text ( STATUS_BEGIN_SIGNING, buf );
259
write_status ( STATUS_BEGIN_SIGNING );
264
myread(int fd, void *buf, size_t count)
268
rc = read( fd, buf, count );
269
} while ( rc == -1 && errno == EINTR );
270
if ( !rc && count ) {
271
static int eof_emmited=0;
272
if ( eof_emmited < 3 ) {
273
*(char*)buf = CONTROL_D;
277
else { /* Ctrl-D not caught - do something reasonable */
278
#ifdef HAVE_DOSISH_SYSTEM
279
raise (SIGINT); /* nothing to hangup under DOS */
281
raise (SIGHUP); /* no more input data */
290
/* Request a string from the client over the command-fd. If GETBOOL
291
is set the function returns a static string (do not free) if the
292
netered value was true or NULL if the entered value was false. */
294
do_get_from_fd ( const char *keyword, int hidden, int getbool )
299
if (statusfp != stdout)
302
write_status_text (getbool? STATUS_GET_BOOL :
303
hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword);
305
for (string = NULL, i = len = 200; ; i++ )
311
string = hidden? xmalloc_secure ( len ) : xmalloc ( len );
313
memcpy (string, save, i );
317
/* Fixme: why not use our read_line function here? */
318
if ( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n' )
320
else if ( string[i] == CONTROL_D )
322
/* Found ETX - Cancel the line and return a sole ETX. */
323
string[0] = CONTROL_D;
330
write_status (STATUS_GOT_IT);
332
if (getbool) /* Fixme: is this correct??? */
333
return (string[0] == 'Y' || string[0] == 'y') ? "" : NULL;
343
if( opt.command_fd != -1 )
345
#ifdef USE_SHM_COPROCESSING
346
if( opt.shm_coprocess )
353
cpr_get_no_help( const char *keyword, const char *prompt )
357
if( opt.command_fd != -1 )
358
return do_get_from_fd ( keyword, 0, 0 );
359
#ifdef USE_SHM_COPROCESSING
360
if( opt.shm_coprocess )
361
return do_shm_get( keyword, 0, 0 );
364
p = tty_get( prompt );
370
cpr_get( const char *keyword, const char *prompt )
374
if( opt.command_fd != -1 )
375
return do_get_from_fd ( keyword, 0, 0 );
376
#ifdef USE_SHM_COPROCESSING
377
if( opt.shm_coprocess )
378
return do_shm_get( keyword, 0, 0 );
381
p = tty_get( prompt );
382
if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
384
display_online_help( keyword );
393
cpr_get_utf8( const char *keyword, const char *prompt )
396
p = cpr_get( keyword, prompt );
398
char *utf8 = native_to_utf8( p );
406
cpr_get_hidden( const char *keyword, const char *prompt )
410
if( opt.command_fd != -1 )
411
return do_get_from_fd ( keyword, 1, 0 );
412
#ifdef USE_SHM_COPROCESSING
413
if( opt.shm_coprocess )
414
return do_shm_get( keyword, 1, 0 );
417
p = tty_get_hidden( prompt );
418
if( *p == '?' && !p[1] ) {
420
display_online_help( keyword );
428
cpr_kill_prompt(void)
430
if( opt.command_fd != -1 )
432
#ifdef USE_SHM_COPROCESSING
433
if( opt.shm_coprocess )
441
cpr_get_answer_is_yes( const char *keyword, const char *prompt )
446
if( opt.command_fd != -1 )
447
return !!do_get_from_fd ( keyword, 0, 1 );
448
#ifdef USE_SHM_COPROCESSING
449
if( opt.shm_coprocess )
450
return !!do_shm_get( keyword, 0, 1 );
453
p = tty_get( prompt );
454
trim_spaces(p); /* it is okay to do this here */
455
if( *p == '?' && !p[1] ) {
457
display_online_help( keyword );
461
yes = answer_is_yes(p);
469
cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
474
if( opt.command_fd != -1 )
475
return !!do_get_from_fd ( keyword, 0, 1 );
476
#ifdef USE_SHM_COPROCESSING
477
if( opt.shm_coprocess )
478
return !!do_shm_get( keyword, 0, 1 );
481
p = tty_get( prompt );
482
trim_spaces(p); /* it is okay to do this here */
483
if( *p == '?' && !p[1] ) {
485
display_online_help( keyword );
489
yes = answer_is_yes_no_quit(p);
498
cpr_get_answer_okay_cancel (const char *keyword,
506
if( opt.command_fd != -1 )
507
answer = do_get_from_fd ( keyword, 0, 0 );
508
#ifdef USE_SHM_COPROCESSING
509
else if( opt.shm_coprocess )
510
answer = do_shm_get( keyword, 0, 0 );
515
yes = answer_is_okay_cancel (answer, def_answer);
522
p = tty_get( prompt );
523
trim_spaces(p); /* it is okay to do this here */
524
if (*p == '?' && !p[1])
527
display_online_help (keyword);
532
yes = answer_is_okay_cancel (p, def_answer);