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_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
)
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.
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
;
185 int lower_limit
= ' ';
186 size_t n
, count
, dowrap
;
188 if( !statusfp
|| !status_currently_allowed (no
) )
189 return; /* Not enabled or allowed. */
196 text
= get_status_string (no
);
197 count
= dowrap
= first
= 1;
200 fprintf (statusfp
, "[GNUPG:] %s ", text
);
202 if (first
&& string
) {
203 fputs (string
, statusfp
);
204 count
+= strlen (string
);
208 for (esc
=0, s
=buffer
, n
=len
; n
&& !esc
; s
++, n
-- ) {
209 if ( *s
== '%' || *(const byte
*)s
<= lower_limit
210 || *(const byte
*)s
== 127 )
212 if ( wrap
&& ++count
> wrap
) {
221 fwrite (buffer
, s
-buffer
, 1, statusfp
);
223 fprintf (statusfp
, "%%%02X", *(const byte
*)s
);
229 putc ( '\n', statusfp
);
232 putc ('\n',statusfp
);
233 if ( fflush (statusfp
) && opt
.exit_on_status_write_error
)
238 write_status_buffer ( int no
, const char *buffer
, size_t len
, int wrap
)
240 write_status_text_and_buffer (no
, NULL
, buffer
, len
, wrap
);
244 /* Print the BEGIN_SIGNING status message. If MD is not NULL it is
245 used to retrieve the hash algorithms used for the message. */
247 write_status_begin_signing (gcry_md_hd_t md
)
255 /* We use a hard coded list of possible algorithms. Using other
256 algorithms than specified by OpenPGP does not make sense
257 anyway. We do this out of performance reasons: Walking all
258 the 110 allowed Ids is not a good idea given the way the
259 check is implemented in libgcrypt. Recall that the only use
260 of this status code is to create the micalg algorithm for
263 for (i
=1; i
<= 11; i
++)
265 if ( gcry_md_is_enabled (md
, i
) && buflen
< DIM(buf
) )
267 snprintf (buf
+buflen
, DIM(buf
) - buflen
- 1,
268 "%sH%d", buflen
? " ":"",i
);
269 buflen
+= strlen (buf
+buflen
);
271 write_status_text ( STATUS_BEGIN_SIGNING
, buf
);
274 write_status ( STATUS_BEGIN_SIGNING
);
279 myread(int fd
, void *buf
, size_t count
)
283 rc
= read( fd
, buf
, count
);
284 } while ( rc
== -1 && errno
== EINTR
);
285 if ( !rc
&& count
) {
286 static int eof_emmited
=0;
287 if ( eof_emmited
< 3 ) {
288 *(char*)buf
= CONTROL_D
;
292 else { /* Ctrl-D not caught - do something reasonable */
293 #ifdef HAVE_DOSISH_SYSTEM
294 raise (SIGINT
); /* nothing to hangup under DOS */
296 raise (SIGHUP
); /* no more input data */
305 /* Request a string from the client over the command-fd. If GETBOOL
306 is set the function returns a static string (do not free) if the
307 netered value was true or NULL if the entered value was false. */
309 do_get_from_fd ( const char *keyword
, int hidden
, int getbool
)
314 if (statusfp
!= stdout
)
317 write_status_text (getbool
? STATUS_GET_BOOL
:
318 hidden
? STATUS_GET_HIDDEN
: STATUS_GET_LINE
, keyword
);
320 for (string
= NULL
, i
= len
= 200; ; i
++ )
326 string
= hidden
? xmalloc_secure ( len
) : xmalloc ( len
);
328 memcpy (string
, save
, i
);
332 /* Fixme: why not use our read_line function here? */
333 if ( myread( opt
.command_fd
, string
+i
, 1) != 1 || string
[i
] == '\n' )
335 else if ( string
[i
] == CONTROL_D
)
337 /* Found ETX - Cancel the line and return a sole ETX. */
338 string
[0] = CONTROL_D
;
345 write_status (STATUS_GOT_IT
);
347 if (getbool
) /* Fixme: is this correct??? */
348 return (string
[0] == 'Y' || string
[0] == 'y') ? "" : NULL
;
358 if( opt
.command_fd
!= -1 )
364 cpr_get_no_help( const char *keyword
, const char *prompt
)
368 if( opt
.command_fd
!= -1 )
369 return do_get_from_fd ( keyword
, 0, 0 );
371 p
= tty_get( prompt
);
377 cpr_get( const char *keyword
, const char *prompt
)
381 if( opt
.command_fd
!= -1 )
382 return do_get_from_fd ( keyword
, 0, 0 );
384 p
= tty_get( prompt
);
385 if( *p
=='?' && !p
[1] && !(keyword
&& !*keyword
)) {
387 display_online_help( keyword
);
396 cpr_get_utf8( const char *keyword
, const char *prompt
)
399 p
= cpr_get( keyword
, prompt
);
401 char *utf8
= native_to_utf8( p
);
409 cpr_get_hidden( const char *keyword
, const char *prompt
)
413 if( opt
.command_fd
!= -1 )
414 return do_get_from_fd ( keyword
, 1, 0 );
416 p
= tty_get_hidden( prompt
);
417 if( *p
== '?' && !p
[1] ) {
419 display_online_help( keyword
);
427 cpr_kill_prompt(void)
429 if( opt
.command_fd
!= -1 )
436 cpr_get_answer_is_yes( const char *keyword
, const char *prompt
)
441 if( opt
.command_fd
!= -1 )
442 return !!do_get_from_fd ( keyword
, 0, 1 );
444 p
= tty_get( prompt
);
445 trim_spaces(p
); /* it is okay to do this here */
446 if( *p
== '?' && !p
[1] ) {
448 display_online_help( keyword
);
452 yes
= answer_is_yes(p
);
460 cpr_get_answer_yes_no_quit( const char *keyword
, const char *prompt
)
465 if( opt
.command_fd
!= -1 )
466 return !!do_get_from_fd ( keyword
, 0, 1 );
468 p
= tty_get( prompt
);
469 trim_spaces(p
); /* it is okay to do this here */
470 if( *p
== '?' && !p
[1] ) {
472 display_online_help( keyword
);
476 yes
= answer_is_yes_no_quit(p
);
485 cpr_get_answer_okay_cancel (const char *keyword
,
493 if( opt
.command_fd
!= -1 )
494 answer
= do_get_from_fd ( keyword
, 0, 0 );
498 yes
= answer_is_okay_cancel (answer
, def_answer
);
505 p
= tty_get( prompt
);
506 trim_spaces(p
); /* it is okay to do this here */
507 if (*p
== '?' && !p
[1])
510 display_online_help (keyword
);
515 yes
= answer_is_okay_cancel (p
, def_answer
);