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 get_status_string ( int no
)
66 case STATUS_ENTER
: s
= "ENTER"; break;
67 case STATUS_LEAVE
: s
= "LEAVE"; break;
68 case STATUS_ABORT
: s
= "ABORT"; break;
69 case STATUS_NEWSIG
: s
= "NEWSIG"; break;
70 case STATUS_GOODSIG
: s
= "GOODSIG"; break;
71 case STATUS_KEYEXPIRED
: s
= "KEYEXPIRED"; break;
72 case STATUS_KEYREVOKED
: s
= "KEYREVOKED"; break;
73 case STATUS_BADSIG
: s
= "BADSIG"; break;
74 case STATUS_ERRSIG
: s
= "ERRSIG"; break;
75 case STATUS_BADARMOR
: s
= "BADARMOR"; break;
76 case STATUS_RSA_OR_IDEA
: s
= "RSA_OR_IDEA"; break;
77 case STATUS_TRUST_UNDEFINED
: s
= "TRUST_UNDEFINED"; break;
78 case STATUS_TRUST_NEVER
: s
= "TRUST_NEVER"; break;
79 case STATUS_TRUST_MARGINAL
: s
= "TRUST_MARGINAL"; break;
80 case STATUS_TRUST_FULLY
: s
= "TRUST_FULLY"; break;
81 case STATUS_TRUST_ULTIMATE
: s
= "TRUST_ULTIMATE"; break;
82 case STATUS_GET_BOOL
: s
= "GET_BOOL"; break;
83 case STATUS_GET_LINE
: s
= "GET_LINE"; break;
84 case STATUS_GET_HIDDEN
: s
= "GET_HIDDEN"; break;
85 case STATUS_GOT_IT
: s
= "GOT_IT"; break;
86 case STATUS_SHM_INFO
: s
= "SHM_INFO"; break;
87 case STATUS_SHM_GET
: s
= "SHM_GET"; break;
88 case STATUS_SHM_GET_BOOL
: s
= "SHM_GET_BOOL"; break;
89 case STATUS_SHM_GET_HIDDEN
: s
= "SHM_GET_HIDDEN"; break;
90 case STATUS_NEED_PASSPHRASE
: s
= "NEED_PASSPHRASE"; break;
91 case STATUS_VALIDSIG
: s
= "VALIDSIG"; break;
92 case STATUS_SIG_ID
: s
= "SIG_ID"; break;
93 case STATUS_ENC_TO
: s
= "ENC_TO"; break;
94 case STATUS_NODATA
: s
= "NODATA"; break;
95 case STATUS_BAD_PASSPHRASE
: s
= "BAD_PASSPHRASE"; break;
96 case STATUS_NO_PUBKEY
: s
= "NO_PUBKEY"; break;
97 case STATUS_NO_SECKEY
: s
= "NO_SECKEY"; break;
98 case STATUS_NEED_PASSPHRASE_SYM
: s
= "NEED_PASSPHRASE_SYM"; break;
99 case STATUS_NEED_PASSPHRASE_PIN
: s
= "NEED_PASSPHRASE_PIN"; break;
100 case STATUS_DECRYPTION_FAILED
: s
= "DECRYPTION_FAILED"; break;
101 case STATUS_DECRYPTION_OKAY
: s
= "DECRYPTION_OKAY"; break;
102 case STATUS_MISSING_PASSPHRASE
: s
= "MISSING_PASSPHRASE"; break;
103 case STATUS_GOOD_PASSPHRASE
: s
= "GOOD_PASSPHRASE"; break;
104 case STATUS_GOODMDC
: s
= "GOODMDC"; break;
105 case STATUS_BADMDC
: s
= "BADMDC"; break;
106 case STATUS_ERRMDC
: s
= "ERRMDC"; break;
107 case STATUS_IMPORTED
: s
= "IMPORTED"; break;
108 case STATUS_IMPORT_OK
: s
= "IMPORT_OK"; break;
109 case STATUS_IMPORT_CHECK
: s
= "IMPORT_CHECK"; break;
110 case STATUS_IMPORT_RES
: s
= "IMPORT_RES"; break;
111 case STATUS_FILE_START
: s
= "FILE_START"; break;
112 case STATUS_FILE_DONE
: s
= "FILE_DONE"; break;
113 case STATUS_FILE_ERROR
: s
= "FILE_ERROR"; break;
114 case STATUS_BEGIN_DECRYPTION
:s
= "BEGIN_DECRYPTION"; break;
115 case STATUS_END_DECRYPTION
: s
= "END_DECRYPTION"; break;
116 case STATUS_BEGIN_ENCRYPTION
:s
= "BEGIN_ENCRYPTION"; break;
117 case STATUS_END_ENCRYPTION
: s
= "END_ENCRYPTION"; break;
118 case STATUS_DELETE_PROBLEM
: s
= "DELETE_PROBLEM"; break;
119 case STATUS_PROGRESS
: s
= "PROGRESS"; break;
120 case STATUS_SIG_CREATED
: s
= "SIG_CREATED"; break;
121 case STATUS_SESSION_KEY
: s
= "SESSION_KEY"; break;
122 case STATUS_NOTATION_NAME
: s
= "NOTATION_NAME" ; break;
123 case STATUS_NOTATION_DATA
: s
= "NOTATION_DATA" ; break;
124 case STATUS_POLICY_URL
: s
= "POLICY_URL" ; break;
125 case STATUS_BEGIN_STREAM
: s
= "BEGIN_STREAM"; break;
126 case STATUS_END_STREAM
: s
= "END_STREAM"; break;
127 case STATUS_KEY_CREATED
: s
= "KEY_CREATED"; break;
128 case STATUS_KEY_NOT_CREATED
: s
= "KEY_NOT_CREATED"; break;
129 case STATUS_USERID_HINT
: s
= "USERID_HINT"; break;
130 case STATUS_UNEXPECTED
: s
= "UNEXPECTED"; break;
131 case STATUS_INV_RECP
: s
= "INV_RECP"; break;
132 case STATUS_NO_RECP
: s
= "NO_RECP"; break;
133 case STATUS_ALREADY_SIGNED
: s
= "ALREADY_SIGNED"; break;
134 case STATUS_SIGEXPIRED
: s
= "SIGEXPIRED deprecated-use-keyexpired-instead"; break;
135 case STATUS_EXPSIG
: s
= "EXPSIG"; break;
136 case STATUS_EXPKEYSIG
: s
= "EXPKEYSIG"; break;
137 case STATUS_REVKEYSIG
: s
= "REVKEYSIG"; break;
138 case STATUS_ATTRIBUTE
: s
= "ATTRIBUTE"; break;
139 case STATUS_CARDCTRL
: s
= "CARDCTRL"; break;
140 case STATUS_PLAINTEXT
: s
= "PLAINTEXT"; break;
141 case STATUS_PLAINTEXT_LENGTH
:s
= "PLAINTEXT_LENGTH"; break;
142 case STATUS_SIG_SUBPACKET
: s
= "SIG_SUBPACKET"; break;
143 case STATUS_SC_OP_SUCCESS
: s
= "SC_OP_SUCCESS"; break;
144 case STATUS_SC_OP_FAILURE
: s
= "SC_OP_FAILURE"; break;
145 case STATUS_BACKUP_KEY_CREATED
:s
="BACKUP_KEY_CREATED"; break;
146 case STATUS_PKA_TRUST_BAD
: s
= "PKA_TRUST_BAD"; break;
147 case STATUS_PKA_TRUST_GOOD
: s
= "PKA_TRUST_GOOD"; break;
148 case STATUS_BEGIN_SIGNING
: s
= "BEGIN_SIGNING"; break;
149 case STATUS_ERROR
: s
= "ERROR"; break;
150 default: s
= "?"; break;
156 /* Return true if the status message NO may currently be issued. We
157 need this to avoid syncronisation problem while auto retrieving a
158 key. There it may happen that a status NODATA is issued for a non
159 available key and the user may falsely interpret this has a missing
162 status_currently_allowed (int no
)
164 if (!glo_ctrl
.in_auto_key_retrieve
)
167 /* We allow some statis anyway, so that import statistics are
168 correct and to avoid problems if the retriebval subsystem will
172 case STATUS_GET_BOOL
:
173 case STATUS_GET_LINE
:
174 case STATUS_GET_HIDDEN
:
176 case STATUS_IMPORTED
:
177 case STATUS_IMPORT_OK
:
178 case STATUS_IMPORT_CHECK
:
179 case STATUS_IMPORT_RES
:
189 set_status_fd ( int fd
)
191 static int last_fd
= -1;
193 if ( fd
!= -1 && last_fd
== fd
)
196 if ( statusfp
&& statusfp
!= stdout
&& statusfp
!= stderr
)
207 statusfp
= fdopen( fd
, "w" );
209 log_fatal("can't open fd %d for status output: %s\n",
210 fd
, strerror(errno
));
214 gcry_set_progress_handler ( progress_cb
, NULL
);
224 write_status ( int no
)
226 write_status_text( no
, NULL
);
230 write_status_text ( int no
, const char *text
)
232 if( !statusfp
|| !status_currently_allowed (no
) )
233 return; /* Not enabled or allowed. */
235 fputs ( "[GNUPG:] ", statusfp
);
236 fputs ( get_status_string (no
), statusfp
);
238 putc ( ' ', statusfp
);
239 for (; *text
; text
++) {
241 fputs ( "\\n", statusfp
);
242 else if (*text
== '\r')
243 fputs ( "\\r", statusfp
);
245 putc ( *(const byte
*)text
, statusfp
);
248 putc ('\n',statusfp
);
249 if ( fflush (statusfp
) && opt
.exit_on_status_write_error
)
255 * Write a status line with a buffer using %XX escapes. If WRAP is >
256 * 0 wrap the line after this length. If STRING is not NULL it will
257 * be prepended to the buffer, no escaping is done for string.
258 * A wrap of -1 forces spaces not to be encoded as %20.
261 write_status_text_and_buffer ( int no
, const char *string
,
262 const char *buffer
, size_t len
, int wrap
)
264 const char *s
, *text
;
266 int lower_limit
= ' ';
267 size_t n
, count
, dowrap
;
269 if( !statusfp
|| !status_currently_allowed (no
) )
270 return; /* Not enabled or allowed. */
277 text
= get_status_string (no
);
278 count
= dowrap
= first
= 1;
281 fprintf (statusfp
, "[GNUPG:] %s ", text
);
283 if (first
&& string
) {
284 fputs (string
, statusfp
);
285 count
+= strlen (string
);
289 for (esc
=0, s
=buffer
, n
=len
; n
&& !esc
; s
++, n
-- ) {
290 if ( *s
== '%' || *(const byte
*)s
<= lower_limit
291 || *(const byte
*)s
== 127 )
293 if ( wrap
&& ++count
> wrap
) {
302 fwrite (buffer
, s
-buffer
, 1, statusfp
);
304 fprintf (statusfp
, "%%%02X", *(const byte
*)s
);
310 putc ( '\n', statusfp
);
313 putc ('\n',statusfp
);
314 if ( fflush (statusfp
) && opt
.exit_on_status_write_error
)
319 write_status_buffer ( int no
, const char *buffer
, size_t len
, int wrap
)
321 write_status_text_and_buffer (no
, NULL
, buffer
, len
, wrap
);
325 /* Print the BEGIN_SIGNING status message. If MD is not NULL it is
326 used retrieve the hash algorithms used for the message. */
328 write_status_begin_signing (gcry_md_hd_t md
)
336 /* We use a hard coded list of possible algorithms. Using other
337 algorithms than specified by OpenPGP does not make sense
338 anyway. We do this out of performance reasons: Walking all
339 the 110 allowed Ids is not a good idea given the way the
340 check is implemented in libgcrypt. Recall that the only use
341 of this status code is to create the micalg algorithm for
344 for (i
=1; i
<= 11; i
++)
346 if ( gcry_md_is_enabled (md
, i
) && buflen
< DIM(buf
) )
348 snprintf (buf
+buflen
, DIM(buf
) - buflen
- 1,
349 "%sH%d", buflen
? " ":"",i
);
350 buflen
+= strlen (buf
+buflen
);
352 write_status_text ( STATUS_BEGIN_SIGNING
, buf
);
355 write_status ( STATUS_BEGIN_SIGNING
);
360 myread(int fd
, void *buf
, size_t count
)
364 rc
= read( fd
, buf
, count
);
365 } while ( rc
== -1 && errno
== EINTR
);
366 if ( !rc
&& count
) {
367 static int eof_emmited
=0;
368 if ( eof_emmited
< 3 ) {
369 *(char*)buf
= CONTROL_D
;
373 else { /* Ctrl-D not caught - do something reasonable */
374 #ifdef HAVE_DOSISH_SYSTEM
375 raise (SIGINT
); /* nothing to hangup under DOS */
377 raise (SIGHUP
); /* no more input data */
387 * Request a string from the client over the command-fd
388 * If bool, returns static string on true (do not free) or NULL for false
391 do_get_from_fd( const char *keyword
, int hidden
, int bool )
399 write_status_text( bool? STATUS_GET_BOOL
:
400 hidden
? STATUS_GET_HIDDEN
: STATUS_GET_LINE
, keyword
);
402 for( string
= NULL
, i
= len
= 200; ; i
++ ) {
406 string
= hidden
? xmalloc_secure ( len
) : xmalloc ( len
);
408 memcpy(string
, save
, i
);
412 /* Hmmm: why not use our read_line function here */
413 if( myread( opt
.command_fd
, string
+i
, 1) != 1 || string
[i
] == '\n' )
415 else if ( string
[i
] == CONTROL_D
) {
416 /* found ETX - cancel the line and return a sole ETX */
417 string
[0] = CONTROL_D
;
424 write_status( STATUS_GOT_IT
);
426 if( bool ) /* Fixme: is this correct??? */
427 return (string
[0] == 'Y' || string
[0] == 'y') ? "" : NULL
;
437 if( opt
.command_fd
!= -1 )
439 #ifdef USE_SHM_COPROCESSING
440 if( opt
.shm_coprocess
)
447 cpr_get_no_help( const char *keyword
, const char *prompt
)
451 if( opt
.command_fd
!= -1 )
452 return do_get_from_fd ( keyword
, 0, 0 );
453 #ifdef USE_SHM_COPROCESSING
454 if( opt
.shm_coprocess
)
455 return do_shm_get( keyword
, 0, 0 );
458 p
= tty_get( prompt
);
464 cpr_get( const char *keyword
, const char *prompt
)
468 if( opt
.command_fd
!= -1 )
469 return do_get_from_fd ( keyword
, 0, 0 );
470 #ifdef USE_SHM_COPROCESSING
471 if( opt
.shm_coprocess
)
472 return do_shm_get( keyword
, 0, 0 );
475 p
= tty_get( prompt
);
476 if( *p
=='?' && !p
[1] && !(keyword
&& !*keyword
)) {
478 display_online_help( keyword
);
487 cpr_get_utf8( const char *keyword
, const char *prompt
)
490 p
= cpr_get( keyword
, prompt
);
492 char *utf8
= native_to_utf8( p
);
500 cpr_get_hidden( const char *keyword
, const char *prompt
)
504 if( opt
.command_fd
!= -1 )
505 return do_get_from_fd ( keyword
, 1, 0 );
506 #ifdef USE_SHM_COPROCESSING
507 if( opt
.shm_coprocess
)
508 return do_shm_get( keyword
, 1, 0 );
511 p
= tty_get_hidden( prompt
);
512 if( *p
== '?' && !p
[1] ) {
514 display_online_help( keyword
);
522 cpr_kill_prompt(void)
524 if( opt
.command_fd
!= -1 )
526 #ifdef USE_SHM_COPROCESSING
527 if( opt
.shm_coprocess
)
535 cpr_get_answer_is_yes( const char *keyword
, const char *prompt
)
540 if( opt
.command_fd
!= -1 )
541 return !!do_get_from_fd ( keyword
, 0, 1 );
542 #ifdef USE_SHM_COPROCESSING
543 if( opt
.shm_coprocess
)
544 return !!do_shm_get( keyword
, 0, 1 );
547 p
= tty_get( prompt
);
548 trim_spaces(p
); /* it is okay to do this here */
549 if( *p
== '?' && !p
[1] ) {
551 display_online_help( keyword
);
555 yes
= answer_is_yes(p
);
563 cpr_get_answer_yes_no_quit( const char *keyword
, const char *prompt
)
568 if( opt
.command_fd
!= -1 )
569 return !!do_get_from_fd ( keyword
, 0, 1 );
570 #ifdef USE_SHM_COPROCESSING
571 if( opt
.shm_coprocess
)
572 return !!do_shm_get( keyword
, 0, 1 );
575 p
= tty_get( prompt
);
576 trim_spaces(p
); /* it is okay to do this here */
577 if( *p
== '?' && !p
[1] ) {
579 display_online_help( keyword
);
583 yes
= answer_is_yes_no_quit(p
);
592 cpr_get_answer_okay_cancel (const char *keyword
,
600 if( opt
.command_fd
!= -1 )
601 answer
= do_get_from_fd ( keyword
, 0, 0 );
602 #ifdef USE_SHM_COPROCESSING
603 else if( opt
.shm_coprocess
)
604 answer
= do_shm_get( keyword
, 0, 0 );
609 yes
= answer_is_okay_cancel (answer
, def_answer
);
616 p
= tty_get( prompt
);
617 trim_spaces(p
); /* it is okay to do this here */
618 if (*p
== '?' && !p
[1])
621 display_online_help (keyword
);
626 yes
= answer_is_okay_cancel (p
, def_answer
);