See ChangeLog: Thu Jan 7 18:00:58 CET 1999 Werner Koch
[gnupg.git] / g10 / plaintext.c
1 /* plaintext.c -  process an plaintext packet
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include "util.h"
28 #include "memory.h"
29 #include "options.h"
30 #include "packet.h"
31 #include "ttyio.h"
32 #include "filter.h"
33 #include "main.h"
34 #include "status.h"
35 #include "i18n.h"
36
37
38 /****************
39  * Defer the last CR,LF
40  */
41 static void
42 special_md_putc( MD_HANDLE md, int c, int *state )
43 {
44     if( c == -1 ) { /* flush */
45         if( *state == 1 ) {
46             md_putc(md, '\r');
47         }
48
49         *state = 0;
50         return;
51     }
52   again:
53     switch( *state ) {
54       case 0:
55         if( c == '\r' )
56             *state = 1;
57         else
58             md_putc(md, c );
59         break;
60       case 1:
61         if( c == '\n' )
62             *state = 2;
63         else {
64             md_putc(md, '\r');
65             *state = 0;
66             goto again;
67         }
68         break;
69       case 2:
70         md_putc(md, '\r');
71         md_putc(md, '\n');
72         *state = 0;
73         goto again;
74       default: BUG();
75     }
76 }
77
78
79 /****************
80  * Handle a plaintext packet.  If MFX is not NULL, update the MDs
81  * Note: we should use the filter stuff here, but we have to add some
82  *       easy mimic to set a read limit, so we calculate only the
83  *       bytes from the plaintext.
84  */
85 int
86 handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
87                   int nooutput, int clearsig )
88 {
89     char *fname = NULL;
90     FILE *fp = NULL;
91     int rc = 0;
92     int c;
93     int convert = pt->mode == 't';
94     int special_state = 0;
95
96     /* create the filename as C string */
97     if( nooutput )
98         ;
99     else if( opt.outfile ) {
100         fname = m_alloc( strlen( opt.outfile ) + 1);
101         strcpy(fname, opt.outfile );
102     }
103     else if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) {
104         log_info(_("data not saved; use option \"--output\" to save it\n"));
105         nooutput = 1;
106     }
107     else {
108         fname = m_alloc( pt->namelen +1 );
109         memcpy( fname, pt->name, pt->namelen );
110         fname[pt->namelen] = 0;
111     }
112
113     if( nooutput )
114         ;
115     else if( !*fname || (*fname=='-' && !fname[1])) {
116         /* no filename or "-" given; write to stdout */
117         fp = stdout;
118     }
119     else if( !overwrite_filep( fname ) ) {
120         rc = G10ERR_CREATE_FILE;
121         goto leave;
122     }
123
124     if( fp || nooutput )
125         ;
126     else if( !(fp = fopen(fname,"wb")) ) {
127         log_error("Error creating `%s': %s\n", fname, strerror(errno) );
128         rc = G10ERR_CREATE_FILE;
129         goto leave;
130     }
131
132     if( pt->len ) {
133         for( ; pt->len; pt->len-- ) {
134             if( (c = iobuf_get(pt->buf)) == -1 ) {
135                 log_error("Problem reading source (%u bytes remaining)\n",
136                                                          (unsigned)pt->len);
137                 rc = G10ERR_READ_FILE;
138                 goto leave;
139             }
140             if( mfx->md ) {
141                 if( 0 && convert && clearsig )
142                     special_md_putc(mfx->md, c, &special_state );
143                 else
144                     md_putc(mfx->md, c );
145             }
146             if( convert && !clearsig && c == '\r' )
147                 continue; /* fixme: this hack might be too simple */
148             if( fp ) {
149                 if( putc( c, fp ) == EOF ) {
150                     log_error("Error writing to `%s': %s\n",
151                                             fname, strerror(errno) );
152                     rc = G10ERR_WRITE_FILE;
153                     goto leave;
154                 }
155             }
156         }
157     }
158     else {
159         while( (c = iobuf_get(pt->buf)) != -1 ) {
160             if( mfx->md ) {
161                 if( 0 && convert && clearsig )
162                     special_md_putc(mfx->md, c, &special_state  );
163                 else
164                     md_putc(mfx->md, c );
165             }
166             if( convert && !clearsig && c == '\r' )
167                 continue; /* fixme: this hack might be too simple */
168             if( fp ) {
169                 if( putc( c, fp ) == EOF ) {
170                     log_error("Error writing to `%s': %s\n",
171                                                 fname, strerror(errno) );
172                     rc = G10ERR_WRITE_FILE;
173                     goto leave;
174                 }
175             }
176         }
177         pt->buf = NULL;
178     }
179     if( 0 && mfx->md && convert && clearsig )
180         special_md_putc(mfx->md, -1, &special_state  ); /* flush */
181
182     if( fp && fp != stdout && fclose(fp) ) {
183         log_error("Error closing `%s': %s\n", fname, strerror(errno) );
184         fp = NULL;
185         rc = G10ERR_WRITE_FILE;
186         goto leave;
187     }
188     fp = NULL;
189
190   leave:
191     if( fp && fp != stdout )
192         fclose(fp);
193     m_free(fname);
194     return rc;
195 }
196
197
198 /****************
199  * Ask for the detached datafile and calculate the digest from it.
200  * INFILE is the name of the input file.
201  */
202 int
203 ask_for_detached_datafile( md_filter_context_t *mfx, const char *inname )
204 {
205     char *answer = NULL;
206     IOBUF fp;
207     int rc = 0;
208     int c;
209
210     fp = open_sigfile( inname ); /* open default file */
211     if( !fp && !opt.batch ) {
212         int any=0;
213         tty_printf("Detached signature.\n");
214         do {
215             m_free(answer);
216             answer = cpr_get("detached_signature.filename",
217                            _("Please enter name of data file: "));
218             cpr_kill_prompt();
219             if( any && !*answer ) {
220                 rc = G10ERR_READ_FILE;
221                 goto leave;
222             }
223             fp = iobuf_open(answer);
224             if( !fp && errno == ENOENT ) {
225                 tty_printf("No such file, try again or hit enter to quit.\n");
226                 any++;
227             }
228             else if( !fp ) {
229                 log_error("can't open `%s': %s\n", answer, strerror(errno) );
230                 rc = G10ERR_READ_FILE;
231                 goto leave;
232             }
233         } while( !fp );
234     }
235
236     if( !fp ) {
237         if( opt.verbose )
238             log_info(_("reading stdin ...\n"));
239         while( (c = getchar()) != EOF ) {
240             if( mfx->md )
241                 md_putc(mfx->md, c );
242         }
243     }
244     else {
245         while( (c = iobuf_get(fp)) != -1 ) {
246             if( mfx->md )
247                 md_putc(mfx->md, c );
248         }
249         iobuf_close(fp);
250     }
251
252   leave:
253     m_free(answer);
254     return rc;
255 }
256
257
258 static void
259 do_hash( MD_HANDLE md, IOBUF fp, int textmode )
260 {
261     text_filter_context_t tfx;
262     int c;
263
264     if( textmode ) {
265         memset( &tfx, 0, sizeof tfx);
266         iobuf_push_filter( fp, text_filter, &tfx );
267     }
268     while( (c = iobuf_get(fp)) != -1 )
269         md_putc(md, c );
270 }
271
272
273 /****************
274  * Hash the given files and append the hash to hash context md.
275  * If FILES is NULL, hash stdin.
276  */
277 int
278 hash_datafiles( MD_HANDLE md, STRLIST files,
279                 const char *sigfilename, int textmode )
280 {
281     IOBUF fp;
282     STRLIST sl=NULL;
283
284     if( !files ) {
285         /* check whether we can opne the signed material */
286         fp = open_sigfile( sigfilename );
287         if( fp ) {
288             do_hash( md, fp, textmode );
289             iobuf_close(fp);
290             return 0;
291         }
292         /* no we can't (no sigfile) - read signed stuff from stdin */
293         add_to_strlist( &sl, "-");
294     }
295     else
296         sl = files;
297
298     for( ; sl; sl = sl->next ) {
299         fp = iobuf_open( sl->d );
300         if( !fp ) {
301             log_error(_("can't open signed data `%s'\n"),
302                                                 print_fname_stdin(sl->d));
303             if( !files )
304                 free_strlist(sl);
305             return G10ERR_OPEN_FILE;
306         }
307         do_hash( md, fp, textmode );
308         iobuf_close(fp);
309     }
310
311     if( !files )
312         free_strlist(sl);
313     return 0;
314 }
315
316