W32 fix
[gnupg.git] / g10 / cpr.c
blob6e89d393dc72e0bdaed2ea80cf4bc81e1f60532b
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);
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.
166 void
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;
171 int esc, first;
172 int lower_limit = ' ';
173 size_t n, count, dowrap;
175 if( !statusfp || !status_currently_allowed (no) )
176 return; /* Not enabled or allowed. */
178 if (wrap == -1) {
179 lower_limit--;
180 wrap = 0;
183 text = get_status_string (no);
184 count = dowrap = first = 1;
185 do {
186 if (dowrap) {
187 fprintf (statusfp, "[GNUPG:] %s ", text );
188 count = dowrap = 0;
189 if (first && string) {
190 fputs (string, statusfp);
191 count += strlen (string);
193 first = 0;
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 )
198 esc = 1;
199 if ( wrap && ++count > wrap ) {
200 dowrap=1;
201 break;
204 if (esc) {
205 s--; n++;
207 if (s != buffer)
208 fwrite (buffer, s-buffer, 1, statusfp );
209 if ( esc ) {
210 fprintf (statusfp, "%%%02X", *(const byte*)s );
211 s++; n--;
213 buffer = s;
214 len = n;
215 if ( dowrap && len )
216 putc ( '\n', statusfp );
217 } while ( len );
219 putc ('\n',statusfp);
220 if ( fflush (statusfp) && opt.exit_on_status_write_error )
221 g10_exit (0);
224 void
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. */
233 void
234 write_status_begin_signing (gcry_md_hd_t md)
236 if (md)
238 char buf[100];
239 size_t buflen;
240 int i;
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
248 PGP/MIME. */
249 buflen = 0;
250 for (i=1; i <= 11; i++)
251 if (i < 4 || i > 7)
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 );
260 else
261 write_status ( STATUS_BEGIN_SIGNING );
265 static int
266 myread(int fd, void *buf, size_t count)
268 int rc;
269 do {
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;
276 rc = 1;
277 eof_emmited++;
279 else { /* Ctrl-D not caught - do something reasonable */
280 #ifdef HAVE_DOSISH_SYSTEM
281 raise (SIGINT); /* nothing to hangup under DOS */
282 #else
283 raise (SIGHUP); /* no more input data */
284 #endif
287 return rc;
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. */
295 static char *
296 do_get_from_fd ( const char *keyword, int hidden, int getbool )
298 int i, len;
299 char *string;
301 if (statusfp != stdout)
302 fflush (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++ )
309 if (i >= len-1 )
311 char *save = string;
312 len += 100;
313 string = hidden? xmalloc_secure ( len ) : xmalloc ( len );
314 if (save)
315 memcpy (string, save, i );
316 else
317 i = 0;
319 /* Fixme: why not use our read_line function here? */
320 if ( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n' )
321 break;
322 else if ( string[i] == CONTROL_D )
324 /* Found ETX - Cancel the line and return a sole ETX. */
325 string[0] = CONTROL_D;
326 i = 1;
327 break;
330 string[i] = 0;
332 write_status (STATUS_GOT_IT);
334 if (getbool) /* Fixme: is this correct??? */
335 return (string[0] == 'Y' || string[0] == 'y') ? "" : NULL;
337 return string;
343 cpr_enabled()
345 if( opt.command_fd != -1 )
346 return 1;
347 #ifdef USE_SHM_COPROCESSING
348 if( opt.shm_coprocess )
349 return 1;
350 #endif
351 return 0;
354 char *
355 cpr_get_no_help( const char *keyword, const char *prompt )
357 char *p;
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 );
364 #endif
365 for(;;) {
366 p = tty_get( prompt );
367 return p;
371 char *
372 cpr_get( const char *keyword, const char *prompt )
374 char *p;
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 );
381 #endif
382 for(;;) {
383 p = tty_get( prompt );
384 if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
385 xfree(p);
386 display_online_help( keyword );
388 else
389 return p;
394 char *
395 cpr_get_utf8( const char *keyword, const char *prompt )
397 char *p;
398 p = cpr_get( keyword, prompt );
399 if( p ) {
400 char *utf8 = native_to_utf8( p );
401 xfree( p );
402 p = utf8;
404 return p;
407 char *
408 cpr_get_hidden( const char *keyword, const char *prompt )
410 char *p;
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 );
417 #endif
418 for(;;) {
419 p = tty_get_hidden( prompt );
420 if( *p == '?' && !p[1] ) {
421 xfree(p);
422 display_online_help( keyword );
424 else
425 return p;
429 void
430 cpr_kill_prompt(void)
432 if( opt.command_fd != -1 )
433 return;
434 #ifdef USE_SHM_COPROCESSING
435 if( opt.shm_coprocess )
436 return;
437 #endif
438 tty_kill_prompt();
439 return;
443 cpr_get_answer_is_yes( const char *keyword, const char *prompt )
445 int yes;
446 char *p;
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 );
453 #endif
454 for(;;) {
455 p = tty_get( prompt );
456 trim_spaces(p); /* it is okay to do this here */
457 if( *p == '?' && !p[1] ) {
458 xfree(p);
459 display_online_help( keyword );
461 else {
462 tty_kill_prompt();
463 yes = answer_is_yes(p);
464 xfree(p);
465 return yes;
471 cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
473 int yes;
474 char *p;
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 );
481 #endif
482 for(;;) {
483 p = tty_get( prompt );
484 trim_spaces(p); /* it is okay to do this here */
485 if( *p == '?' && !p[1] ) {
486 xfree(p);
487 display_online_help( keyword );
489 else {
490 tty_kill_prompt();
491 yes = answer_is_yes_no_quit(p);
492 xfree(p);
493 return yes;
500 cpr_get_answer_okay_cancel (const char *keyword,
501 const char *prompt,
502 int def_answer)
504 int yes;
505 char *answer = NULL;
506 char *p;
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 );
513 #endif
515 if (answer)
517 yes = answer_is_okay_cancel (answer, def_answer);
518 xfree (answer);
519 return yes;
522 for(;;)
524 p = tty_get( prompt );
525 trim_spaces(p); /* it is okay to do this here */
526 if (*p == '?' && !p[1])
528 xfree(p);
529 display_online_help (keyword);
531 else
533 tty_kill_prompt();
534 yes = answer_is_okay_cancel (p, def_answer);
535 xfree(p);
536 return yes;