* options.h, g10.c (main), textfilter.c (len_without_trailing_ws): Removed
[gnupg.git] / g10 / textfilter.c
1 /* textfilter.c
2  * Copyright (C) 1998, 1999, 2000, 2001, 2004 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
28 #include "errors.h"
29 #include "iobuf.h"
30 #include "memory.h"
31 #include "util.h"
32 #include "filter.h"
33 #include "i18n.h"
34 #include "options.h"
35
36 #ifdef HAVE_DOSISH_SYSTEM
37 #define LF "\r\n"
38 #else
39 #define LF "\n"
40 #endif
41
42 #define MAX_LINELEN 19995 /* a little bit smaller than in armor.c */
43                           /* to make sure that a warning is displayed while */
44                           /* creating a message */
45
46 static unsigned
47 len_without_trailing_chars( byte *line, unsigned len, const char *trimchars )
48 {
49     byte *p, *mark;
50     unsigned n;
51
52     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
53         if( strchr( trimchars, *p ) ) {
54             if( !mark )
55                 mark = p;
56         }
57         else
58             mark = NULL;
59     }
60
61     return mark? (mark - line) : len;
62 }
63
64 static int
65 standard( text_filter_context_t *tfx, IOBUF a,
66           byte *buf, size_t size, size_t *ret_len)
67 {
68     int rc=0;
69     size_t len = 0;
70     unsigned maxlen;
71
72     assert( size > 10 );
73     size -= 2;  /* reserve 2 bytes to append CR,LF */
74     while( !rc && len < size ) {
75         int lf_seen;
76
77         while( len < size && tfx->buffer_pos < tfx->buffer_len )
78             buf[len++] = tfx->buffer[tfx->buffer_pos++];
79         if( len >= size )
80             continue;
81
82         /* read the next line */
83         maxlen = MAX_LINELEN;
84         tfx->buffer_pos = 0;
85         tfx->buffer_len = iobuf_read_line( a, &tfx->buffer,
86                                            &tfx->buffer_size, &maxlen );
87         if( !maxlen )
88             tfx->truncated++;
89         if( !tfx->buffer_len ) {
90             if( !len )
91                 rc = -1; /* eof */
92             break;
93         }
94         lf_seen = tfx->buffer[tfx->buffer_len-1] == '\n';
95
96         /* The story behind this is that 2440 says that textmode
97            hashes should canonicalize line endings to CRLF and remove
98            spaces and tabs.  2440bis-12 says to just canonicalize to
99            CRLF.  So, we default to the 2440bis-12 behavior, but
100            revert to the strict 2440 behavior if the user specifies
101            --rfc2440. In practical terms this makes no difference to
102            any signatures in the real world except for a textmode
103            detached signature.  PGP always used the 2440bis-12 (1991)
104            behavior (ignoring 2440 itself), so this actually makes us
105            compatible with PGP textmode detached signatures for the
106            first time. */
107         if(opt.strict_2440_line_endings)
108           tfx->buffer_len=trim_trailing_chars(tfx->buffer,tfx->buffer_len,
109                                               " \t\r\n");
110         else
111           tfx->buffer_len=trim_trailing_chars(tfx->buffer,tfx->buffer_len,
112                                               "\r\n");
113
114         if( lf_seen ) {
115             tfx->buffer[tfx->buffer_len++] = '\r';
116             tfx->buffer[tfx->buffer_len++] = '\n';
117         }
118     }
119     *ret_len = len;
120     return rc;
121 }
122
123
124
125
126 /****************
127  * The filter is used to make canonical text: Lines are terminated by
128  * CR, LF, trailing white spaces are removed.
129  */
130 int
131 text_filter( void *opaque, int control,
132              IOBUF a, byte *buf, size_t *ret_len)
133 {
134     size_t size = *ret_len;
135     text_filter_context_t *tfx = opaque;
136     int rc=0;
137
138     if( control == IOBUFCTRL_UNDERFLOW ) {
139         rc = standard( tfx, a, buf, size, ret_len );
140     }
141     else if( control == IOBUFCTRL_FREE ) {
142         if( tfx->truncated )
143             log_error(_("can't handle text lines longer than %d characters\n"),
144                         MAX_LINELEN );
145         m_free( tfx->buffer );
146         tfx->buffer = NULL;
147     }
148     else if( control == IOBUFCTRL_DESC )
149         *(char**)buf = "text_filter";
150     return rc;
151 }
152
153
154 /****************
155  * Copy data from INP to OUT and do some escaping if requested.
156  * md is updated as required by rfc2440
157  */
158 int
159 copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md,
160                     int escape_dash, int escape_from, int pgp2mode )
161 {
162     unsigned maxlen;
163     byte *buffer = NULL;    /* malloced buffer */
164     unsigned bufsize;       /* and size of this buffer */
165     unsigned n;
166     int truncated = 0;
167     int pending_lf = 0;
168
169     if( !opt.pgp2_workarounds )
170         pgp2mode = 0;
171
172     if( !escape_dash )
173         escape_from = 0;
174
175     for(;;) {
176         maxlen = MAX_LINELEN;
177         n = iobuf_read_line( inp, &buffer, &bufsize, &maxlen );
178         if( !maxlen )
179             truncated++;
180
181         if( !n )
182             break; /* read_line has returned eof */
183
184         /* update the message digest */
185         if( escape_dash ) {
186             if( pending_lf ) {
187                 md_putc( md, '\r' );
188                 md_putc( md, '\n' );
189             }
190             md_write( md, buffer,
191                      len_without_trailing_chars( buffer, n,
192                                                  pgp2mode? " \r\n":" \t\r\n"));
193         }
194         else
195             md_write( md, buffer, n );
196         pending_lf = buffer[n-1] == '\n';
197
198         /* write the output */
199         if(    ( escape_dash && *buffer == '-')
200             || ( escape_from && n > 4 && !memcmp(buffer, "From ", 5 ) ) ) {
201             iobuf_put( out, '-' );
202             iobuf_put( out, ' ' );
203         }
204
205 #if  0 /*defined(HAVE_DOSISH_SYSTEM)*/
206         /* We don't use this anymore because my interpretation of rfc2440 7.1
207          * is that there is no conversion needed.  If one decides to
208          * clearsign a unix file on a DOS box he will get a mixed line endings.
209          * If at some point it turns out, that a conversion is a nice feature
210          * we can make an option out of it.
211          */
212         /* make sure the lines do end in CR,LF */
213         if( n > 1 && ( (buffer[n-2] == '\r' && buffer[n-1] == '\n' )
214                             || (buffer[n-2] == '\n' && buffer[n-1] == '\r'))) {
215             iobuf_write( out, buffer, n-2 );
216             iobuf_put( out, '\r');
217             iobuf_put( out, '\n');
218         }
219         else if( n && buffer[n-1] == '\n' ) {
220             iobuf_write( out, buffer, n-1 );
221             iobuf_put( out, '\r');
222             iobuf_put( out, '\n');
223         }
224         else
225             iobuf_write( out, buffer, n );
226
227 #else
228         iobuf_write( out, buffer, n );
229 #endif
230     }
231
232     /* at eof */
233     if( !pending_lf ) { /* make sure that the file ends with a LF */
234         iobuf_writestr( out, LF );
235         if( !escape_dash )
236             md_putc( md, '\n' );
237     }
238
239     if( truncated )
240         log_info(_("input line longer than %d characters\n"), MAX_LINELEN );
241
242     return 0; /* okay */
243 }