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
)
53 if ( printchar
== '\n' && !strcmp (what
, "primegen") )
54 snprintf (buf
, sizeof buf
-1, "%.20s X 100 100", what
);
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
68 status_currently_allowed (int no
)
70 if (!glo_ctrl
.in_auto_key_retrieve
)
73 /* We allow some statis anyway, so that import statistics are
74 correct and to avoid problems if the retriebval subsystem will
80 case STATUS_GET_HIDDEN
:
83 case STATUS_IMPORT_OK
:
84 case STATUS_IMPORT_CHECK
:
85 case STATUS_IMPORT_RES
:
95 set_status_fd ( int fd
)
97 static int last_fd
= -1;
99 if ( fd
!= -1 && last_fd
== fd
)
102 if ( statusfp
&& statusfp
!= stdout
&& statusfp
!= stderr
)
113 statusfp
= fdopen( fd
, "w" );
115 log_fatal("can't open fd %d for status output: %s\n",
116 fd
, strerror(errno
));
120 gcry_set_progress_handler ( progress_cb
, NULL
);
130 write_status ( int no
)
132 write_status_text( no
, NULL
);
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
);
144 putc ( ' ', statusfp
);
145 for (; *text
; text
++) {
147 fputs ( "\\n", statusfp
);
148 else if (*text
== '\r')
149 fputs ( "\\r", statusfp
);
151 putc ( *(const byte
*)text
, statusfp
);
154 putc ('\n',statusfp
);
155 if ( fflush (statusfp
) && opt
.exit_on_status_write_error
)
161 * Write a status line with a buffer using %XX escapes. If WRAP is >
162 * 0 wrap the line after this length. If STRING is not NULL it will
163 * be prepended to the buffer, no escaping is done for string.
164 * A wrap of -1 forces spaces not to be encoded as %20.
167 write_status_text_and_buffer ( int no
, const char *string
,
168 const char *buffer
, size_t len
, int wrap
)
170 const char *s
, *text
;
172 int lower_limit
= ' ';
173 size_t n
, count
, dowrap
;
175 if( !statusfp
|| !status_currently_allowed (no
) )
176 return; /* Not enabled or allowed. */
183 text
= get_status_string (no
);
184 count
= dowrap
= first
= 1;
187 fprintf (statusfp
, "[GNUPG:] %s ", text
);
189 if (first
&& string
) {
190 fputs (string
, statusfp
);
191 count
+= strlen (string
);
195 for (esc
=0, s
=buffer
, n
=len
; n
&& !esc
; s
++, n
-- ) {
196 if ( *s
== '%' || *(const byte
*)s
<= lower_limit
197 || *(const byte
*)s
== 127 )
199 if ( wrap
&& ++count
> wrap
) {
208 fwrite (buffer
, s
-buffer
, 1, statusfp
);
210 fprintf (statusfp
, "%%%02X", *(const byte
*)s
);
216 putc ( '\n', statusfp
);
219 putc ('\n',statusfp
);
220 if ( fflush (statusfp
) && opt
.exit_on_status_write_error
)
225 write_status_buffer ( int no
, const char *buffer
, size_t len
, int wrap
)
227 write_status_text_and_buffer (no
, NULL
, buffer
, len
, wrap
);
231 /* Print the BEGIN_SIGNING status message. If MD is not NULL it is
232 used to retrieve the hash algorithms used for the message. */
234 write_status_begin_signing (gcry_md_hd_t md
)
242 /* We use a hard coded list of possible algorithms. Using other
243 algorithms than specified by OpenPGP does not make sense
244 anyway. We do this out of performance reasons: Walking all
245 the 110 allowed Ids is not a good idea given the way the
246 check is implemented in libgcrypt. Recall that the only use
247 of this status code is to create the micalg algorithm for
250 for (i
=1; i
<= 11; i
++)
252 if ( gcry_md_is_enabled (md
, i
) && buflen
< DIM(buf
) )
254 snprintf (buf
+buflen
, DIM(buf
) - buflen
- 1,
255 "%sH%d", buflen
? " ":"",i
);
256 buflen
+= strlen (buf
+buflen
);
258 write_status_text ( STATUS_BEGIN_SIGNING
, buf
);
261 write_status ( STATUS_BEGIN_SIGNING
);
266 myread(int fd
, void *buf
, size_t count
)
270 rc
= read( fd
, buf
, count
);
271 } while ( rc
== -1 && errno
== EINTR
);
272 if ( !rc
&& count
) {
273 static int eof_emmited
=0;
274 if ( eof_emmited
< 3 ) {
275 *(char*)buf
= CONTROL_D
;
279 else { /* Ctrl-D not caught - do something reasonable */
280 #ifdef HAVE_DOSISH_SYSTEM
281 raise (SIGINT
); /* nothing to hangup under DOS */
283 raise (SIGHUP
); /* no more input data */
292 /* Request a string from the client over the command-fd. If GETBOOL
293 is set the function returns a static string (do not free) if the
294 netered value was true or NULL if the entered value was false. */
296 do_get_from_fd ( const char *keyword
, int hidden
, int getbool
)
301 if (statusfp
!= stdout
)
304 write_status_text (getbool
? STATUS_GET_BOOL
:
305 hidden
? STATUS_GET_HIDDEN
: STATUS_GET_LINE
, keyword
);
307 for (string
= NULL
, i
= len
= 200; ; i
++ )
313 string
= hidden
? xmalloc_secure ( len
) : xmalloc ( len
);
315 memcpy (string
, save
, i
);
319 /* Fixme: why not use our read_line function here? */
320 if ( myread( opt
.command_fd
, string
+i
, 1) != 1 || string
[i
] == '\n' )
322 else if ( string
[i
] == CONTROL_D
)
324 /* Found ETX - Cancel the line and return a sole ETX. */
325 string
[0] = CONTROL_D
;
332 write_status (STATUS_GOT_IT
);
334 if (getbool
) /* Fixme: is this correct??? */
335 return (string
[0] == 'Y' || string
[0] == 'y') ? "" : NULL
;
345 if( opt
.command_fd
!= -1 )
347 #ifdef USE_SHM_COPROCESSING
348 if( opt
.shm_coprocess
)
355 cpr_get_no_help( const char *keyword
, const char *prompt
)
359 if( opt
.command_fd
!= -1 )
360 return do_get_from_fd ( keyword
, 0, 0 );
361 #ifdef USE_SHM_COPROCESSING
362 if( opt
.shm_coprocess
)
363 return do_shm_get( keyword
, 0, 0 );
366 p
= tty_get( prompt
);
372 cpr_get( const char *keyword
, const char *prompt
)
376 if( opt
.command_fd
!= -1 )
377 return do_get_from_fd ( keyword
, 0, 0 );
378 #ifdef USE_SHM_COPROCESSING
379 if( opt
.shm_coprocess
)
380 return do_shm_get( keyword
, 0, 0 );
383 p
= tty_get( prompt
);
384 if( *p
=='?' && !p
[1] && !(keyword
&& !*keyword
)) {
386 display_online_help( keyword
);
395 cpr_get_utf8( const char *keyword
, const char *prompt
)
398 p
= cpr_get( keyword
, prompt
);
400 char *utf8
= native_to_utf8( p
);
408 cpr_get_hidden( const char *keyword
, const char *prompt
)
412 if( opt
.command_fd
!= -1 )
413 return do_get_from_fd ( keyword
, 1, 0 );
414 #ifdef USE_SHM_COPROCESSING
415 if( opt
.shm_coprocess
)
416 return do_shm_get( keyword
, 1, 0 );
419 p
= tty_get_hidden( prompt
);
420 if( *p
== '?' && !p
[1] ) {
422 display_online_help( keyword
);
430 cpr_kill_prompt(void)
432 if( opt
.command_fd
!= -1 )
434 #ifdef USE_SHM_COPROCESSING
435 if( opt
.shm_coprocess
)
443 cpr_get_answer_is_yes( const char *keyword
, const char *prompt
)
448 if( opt
.command_fd
!= -1 )
449 return !!do_get_from_fd ( keyword
, 0, 1 );
450 #ifdef USE_SHM_COPROCESSING
451 if( opt
.shm_coprocess
)
452 return !!do_shm_get( keyword
, 0, 1 );
455 p
= tty_get( prompt
);
456 trim_spaces(p
); /* it is okay to do this here */
457 if( *p
== '?' && !p
[1] ) {
459 display_online_help( keyword
);
463 yes
= answer_is_yes(p
);
471 cpr_get_answer_yes_no_quit( const char *keyword
, const char *prompt
)
476 if( opt
.command_fd
!= -1 )
477 return !!do_get_from_fd ( keyword
, 0, 1 );
478 #ifdef USE_SHM_COPROCESSING
479 if( opt
.shm_coprocess
)
480 return !!do_shm_get( keyword
, 0, 1 );
483 p
= tty_get( prompt
);
484 trim_spaces(p
); /* it is okay to do this here */
485 if( *p
== '?' && !p
[1] ) {
487 display_online_help( keyword
);
491 yes
= answer_is_yes_no_quit(p
);
500 cpr_get_answer_okay_cancel (const char *keyword
,
508 if( opt
.command_fd
!= -1 )
509 answer
= do_get_from_fd ( keyword
, 0, 0 );
510 #ifdef USE_SHM_COPROCESSING
511 else if( opt
.shm_coprocess
)
512 answer
= do_shm_get( keyword
, 0, 0 );
517 yes
= answer_is_okay_cancel (answer
, def_answer
);
524 p
= tty_get( prompt
);
525 trim_spaces(p
); /* it is okay to do this here */
526 if (*p
== '?' && !p
[1])
529 display_online_help (keyword
);
534 yes
= answer_is_okay_cancel (p
, def_answer
);