1 /* literal.c - Literal packet filters
2 * Copyright (C) 2002-2012 Free Software Foundation, Inc.
6 * This file is part of OpenCDK.
8 * The OpenCDK library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
30 #include <gnutls_int.h>
31 #include <gnutls_str.h>
34 /* Duplicate the string @s but strip of possible
35 relative folder names of it. */
37 dup_trim_filename (const char *s
)
43 p
= strrchr (s
, '\\');
45 return cdk_strdup (s
);
46 return cdk_strdup (p
+ 1);
51 literal_decode (void *data
, FILE * in
, FILE * out
)
53 literal_filter_t
*pfx
= data
;
62 _cdk_log_debug ("literal filter: decode\n");
64 if (!pfx
|| !in
|| !out
)
67 rc
= _cdk_stream_fpopen (in
, STREAMCTL_READ
, &si
);
72 rc
= cdk_pkt_read (si
, pkt
);
73 if (rc
|| pkt
->pkttype
!= CDK_PKT_LITERAL
)
75 cdk_pkt_release (pkt
);
76 cdk_stream_close (si
);
77 return !rc
? CDK_Inv_Packet
: rc
;
80 rc
= _cdk_stream_fpopen (out
, STREAMCTL_WRITE
, &so
);
83 cdk_pkt_release (pkt
);
84 cdk_stream_close (si
);
88 pt
= pkt
->pkt
.literal
;
91 if (pfx
->filename
&& pt
->namelen
> 0)
93 /* The name in the literal packet is more authorative. */
94 cdk_free (pfx
->filename
);
95 pfx
->filename
= dup_trim_filename (pt
->name
);
97 else if (!pfx
->filename
&& pt
->namelen
> 0)
98 pfx
->filename
= dup_trim_filename (pt
->name
);
99 else if (!pt
->namelen
&& !pfx
->filename
&& pfx
->orig_filename
)
101 /* In this case, we need to derrive the output file name
102 from the original name and cut off the OpenPGP extension.
103 If this is not possible, we return an error. */
104 if (!stristr (pfx
->orig_filename
, ".gpg") &&
105 !stristr (pfx
->orig_filename
, ".pgp") &&
106 !stristr (pfx
->orig_filename
, ".asc"))
108 cdk_pkt_release (pkt
);
109 cdk_stream_close (si
);
110 cdk_stream_close (so
);
112 ("literal filter: no file name and no PGP extension\n");
115 _cdk_log_debug ("literal filter: derrive file name from original\n");
116 pfx
->filename
= dup_trim_filename (pfx
->orig_filename
);
117 pfx
->filename
[strlen (pfx
->filename
) - 4] = '\0';
122 _cdk_log_debug ("literal_decode: part on %d size %lu\n",
123 (int) pfx
->blkmode
.on
, (unsigned long)pfx
->blkmode
.size
);
125 bufsize
= pfx
->blkmode
.size
;
127 bufsize
= pt
->len
< DIM (buf
) ? pt
->len
: DIM (buf
);
128 nread
= cdk_stream_read (pt
->buf
, buf
, bufsize
);
134 if (pfx
->md_initialized
)
135 _gnutls_hash (&pfx
->md
, buf
, nread
);
136 cdk_stream_write (so
, buf
, nread
);
140 pfx
->blkmode
.size
= _cdk_pkt_read_len (in
, &pfx
->blkmode
.on
);
141 if ((ssize_t
) pfx
->blkmode
.size
== EOF
)
142 return CDK_Inv_Packet
;
144 if (pt
->len
<= 0 && !pfx
->blkmode
.on
)
148 cdk_stream_close (si
);
149 cdk_stream_close (so
);
150 cdk_pkt_release (pkt
);
156 intmode_to_char (int mode
)
160 case CDK_LITFMT_BINARY
:
162 case CDK_LITFMT_TEXT
:
164 case CDK_LITFMT_UNICODE
:
175 literal_encode (void *data
, FILE * in
, FILE * out
)
177 literal_filter_t
*pfx
= data
;
178 cdk_pkt_literal_t pt
;
184 _cdk_log_debug ("literal filter: encode\n");
186 if (!pfx
|| !in
|| !out
)
187 return CDK_Inv_Value
;
190 pfx
->filename
= cdk_strdup ("_CONSOLE");
192 return CDK_Out_Of_Core
;
195 rc
= _cdk_stream_fpopen (in
, STREAMCTL_READ
, &si
);
199 filelen
= strlen (pfx
->filename
);
201 pt
= pkt
->pkt
.literal
= cdk_calloc (1, sizeof *pt
+ filelen
);
202 pt
->name
= (char *) pt
+ sizeof (*pt
);
205 cdk_pkt_release (pkt
);
206 cdk_stream_close (si
);
207 return CDK_Out_Of_Core
;
209 memcpy (pt
->name
, pfx
->filename
, filelen
);
210 pt
->namelen
= filelen
;
211 pt
->name
[pt
->namelen
] = '\0';
212 pt
->timestamp
= (u32
) gnutls_time (NULL
);
213 pt
->mode
= intmode_to_char (pfx
->mode
);
214 pt
->len
= cdk_stream_get_length (si
);
217 pkt
->pkttype
= CDK_PKT_LITERAL
;
218 rc
= _cdk_pkt_write_fp (out
, pkt
);
220 cdk_pkt_release (pkt
);
221 cdk_stream_close (si
);
227 _cdk_filter_literal (void *data
, int ctl
, FILE * in
, FILE * out
)
229 if (ctl
== STREAMCTL_READ
)
230 return literal_decode (data
, in
, out
);
231 else if (ctl
== STREAMCTL_WRITE
)
232 return literal_encode (data
, in
, out
);
233 else if (ctl
== STREAMCTL_FREE
)
235 literal_filter_t
*pfx
= data
;
238 _cdk_log_debug ("free literal filter\n");
239 cdk_free (pfx
->filename
);
240 pfx
->filename
= NULL
;
241 cdk_free (pfx
->orig_filename
);
242 pfx
->orig_filename
= NULL
;
251 text_encode (void *data
, FILE * in
, FILE * out
)
257 return CDK_Inv_Value
;
259 /* FIXME: This code does not work for very long lines. */
262 /* give space for trim_string \r\n */
263 s
= fgets (buf
, DIM (buf
) - 3, in
);
266 _cdk_trim_string (buf
);
267 _gnutls_str_cat (buf
, sizeof(buf
), "\r\n");
268 fwrite (buf
, 1, strlen (buf
), out
);
276 text_decode (void *data
, FILE * in
, FILE * out
)
278 text_filter_t
*tfx
= data
;
282 if (!tfx
|| !in
|| !out
)
283 return CDK_Inv_Value
;
287 s
= fgets (buf
, DIM (buf
) - 1, in
);
290 _cdk_trim_string (buf
);
291 fwrite (buf
, 1, strlen (buf
), out
);
292 fwrite (tfx
->lf
, 1, strlen (tfx
->lf
), out
);
300 _cdk_filter_text (void *data
, int ctl
, FILE * in
, FILE * out
)
302 if (ctl
== STREAMCTL_READ
)
303 return text_encode (data
, in
, out
);
304 else if (ctl
== STREAMCTL_WRITE
)
305 return text_decode (data
, in
, out
);
306 else if (ctl
== STREAMCTL_FREE
)
308 text_filter_t
*tfx
= data
;
311 _cdk_log_debug ("free text filter\n");