1 |
/* data.c |
2 |
* Copyright (C) 2000-2003 Werner Koch (dd9jn), g10 Code GmbH |
3 |
* Copyright (C) 2001-2004 Timo Schulz |
4 |
* |
5 |
* This file is part of MyGPGME. |
6 |
* |
7 |
* MyGPGME 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 2 of the License, or |
10 |
* (at your option) any later version. |
11 |
* |
12 |
* MyGPGME 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. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with this program; if not, write to the Free Software |
19 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
20 |
*/ |
21 |
|
22 |
#include <stdio.h> |
23 |
#include <stdlib.h> |
24 |
#include <string.h> |
25 |
#include <assert.h> |
26 |
#include <errno.h> |
27 |
#include <sys/types.h> |
28 |
#include <sys/stat.h> |
29 |
#include <process.h> |
30 |
#include <io.h> |
31 |
#include <windows.h> |
32 |
|
33 |
#include "util.h" |
34 |
#include "context.h" |
35 |
#include "ops.h" |
36 |
|
37 |
#define ALLOC_CHUNK 1024 |
38 |
#define MAX_FILESIZE 16777216 |
39 |
|
40 |
static char pgm_string[128] = "OpenPrivacy"; |
41 |
|
42 |
|
43 |
/** |
44 |
* gpgme_data_new: |
45 |
* @r_dh: returns the new data object |
46 |
* |
47 |
* Create a new data object without any content. |
48 |
* |
49 |
* Return value: An error value or 0 on success |
50 |
**/ |
51 |
gpgme_error_t |
52 |
gpgme_data_new (gpgme_data_t * r_dh) |
53 |
{ |
54 |
gpgme_data_t dh; |
55 |
|
56 |
if (!r_dh) |
57 |
return mk_error (Invalid_Value); |
58 |
*r_dh = NULL; |
59 |
dh = calloc (1, sizeof *dh); |
60 |
if (!dh) |
61 |
return mk_error (Out_Of_Core); |
62 |
dh->mode = GPGME_DATA_MODE_INOUT; |
63 |
*r_dh = dh; |
64 |
return 0; |
65 |
} /* gpgme_data_new */ |
66 |
|
67 |
|
68 |
/** |
69 |
* gpgme_data_new_from_mem: |
70 |
* @r_dh: Returns a new data object. |
71 |
* @buffer: Initialize with this. |
72 |
* @size: Size of the buffer |
73 |
* @copy: Flag wether a copy of the buffer should be used. |
74 |
* |
75 |
* Create a new data object and initialize with data |
76 |
* from the memory. A @copy with value %TRUE creates a copy of the |
77 |
* memory, a value of %FALSE uses the original memory of @buffer and the |
78 |
* caller has to make sure that this buffer is valid until gpgme_release_data() |
79 |
* is called. |
80 |
* |
81 |
* Return value: |
82 |
**/ |
83 |
gpgme_error_t |
84 |
gpgme_data_new_from_mem (gpgme_data_t * r_dh, |
85 |
const char * buffer, size_t size, int copy) |
86 |
{ |
87 |
gpgme_data_t dh; |
88 |
gpgme_error_t err; |
89 |
char * p; |
90 |
|
91 |
if (!r_dh || !buffer) |
92 |
return mk_error (Invalid_Value); |
93 |
*r_dh = NULL; |
94 |
err = gpgme_data_new (&dh); |
95 |
if (err) |
96 |
return err; |
97 |
dh->len = size; |
98 |
if (copy) { |
99 |
p = dh->private_buffer = malloc (size? size : 1); |
100 |
if (!p) { |
101 |
gpgme_data_release (dh); |
102 |
return mk_error (Out_Of_Core); |
103 |
} |
104 |
dh->private_len = size; |
105 |
memcpy (dh->private_buffer, buffer, size); |
106 |
dh->data = dh->private_buffer; |
107 |
dh->writepos = size; |
108 |
} |
109 |
else |
110 |
dh->data = buffer; |
111 |
dh->type = GPGME_DATA_TYPE_MEM; |
112 |
*r_dh = dh; |
113 |
return 0; |
114 |
} |
115 |
|
116 |
|
117 |
gpgme_error_t |
118 |
gpgme_data_new_with_read_cb (gpgme_data_t *r_dh, |
119 |
int (*read_cb)(void*,char *,size_t,size_t*), |
120 |
void *read_cb_value) |
121 |
{ |
122 |
gpgme_data_t dh; |
123 |
gpgme_error_t err; |
124 |
|
125 |
if (!r_dh || !read_cb) |
126 |
return mk_error (Invalid_Value); |
127 |
*r_dh = NULL; |
128 |
err = gpgme_data_new (&dh); |
129 |
if (err) |
130 |
return err; |
131 |
dh->type = GPGME_DATA_TYPE_CB; |
132 |
dh->mode = GPGME_DATA_MODE_OUT; |
133 |
dh->read_cb = read_cb; |
134 |
dh->read_cb_value = read_cb_value; |
135 |
|
136 |
*r_dh = dh; |
137 |
return 0; |
138 |
} |
139 |
|
140 |
/** |
141 |
* gpgme_data_new_from_file: |
142 |
* @r_dh: returns the new data object |
143 |
* @fname: filename |
144 |
* |
145 |
* Create a new data object and initialize it with the content of |
146 |
* the file @file. If @copy is %True the file is immediately read in |
147 |
* adn closed. @copy of %False is not yet supportted. |
148 |
* |
149 |
* Return value: An error code or 0 on success. If the error code is |
150 |
* %GPGME_File_Error, the OS error code is held in %errno. |
151 |
**/ |
152 |
gpgme_error_t |
153 |
gpgme_data_new_from_file (gpgme_data_t * r_dh, const char * fname) |
154 |
{ |
155 |
gpgme_data_t dh; |
156 |
gpgme_error_t err; |
157 |
struct stat st; |
158 |
FILE *fp; |
159 |
|
160 |
if (!r_dh) |
161 |
return mk_error (Invalid_Value); |
162 |
*r_dh = NULL; |
163 |
if (!fname) |
164 |
return mk_error (Invalid_Value); |
165 |
|
166 |
err = gpgme_data_new (&dh); |
167 |
if (err) |
168 |
return err; |
169 |
|
170 |
fp = my_fopen (fname, "rb"); |
171 |
if (!fp) { |
172 |
int save_errno = errno; |
173 |
gpgme_data_release (dh); |
174 |
errno = save_errno; |
175 |
return mk_error (File_Error); |
176 |
} |
177 |
|
178 |
if (fstat (fileno (fp), &st)) { |
179 |
int save_errno = errno; |
180 |
fclose (fp); |
181 |
gpgme_data_release (dh); |
182 |
errno = save_errno; |
183 |
return mk_error (File_Error); |
184 |
} |
185 |
|
186 |
/* Check to disallow to load large files */ |
187 |
if (st.st_size > MAX_FILESIZE) { |
188 |
fclose (fp); |
189 |
gpgme_data_release (dh); |
190 |
return mk_error (General_Error); |
191 |
} |
192 |
dh->private_buffer = malloc (st.st_size? st.st_size : 1); |
193 |
if (!dh->private_buffer) { |
194 |
fclose (fp); |
195 |
gpgme_data_release (dh); |
196 |
return mk_error (Out_Of_Core); |
197 |
} |
198 |
dh->private_len = st.st_size; |
199 |
|
200 |
if (fread (dh->private_buffer, dh->private_len, 1, fp) != 1) { |
201 |
int save_errno = errno; |
202 |
fclose (fp); |
203 |
gpgme_data_release (dh); |
204 |
errno = save_errno; |
205 |
return mk_error (File_Error); |
206 |
} |
207 |
fclose (fp); |
208 |
|
209 |
dh->len = dh->private_len; |
210 |
dh->data = dh->private_buffer; |
211 |
dh->writepos = dh->len; |
212 |
dh->type = GPGME_DATA_TYPE_MEM; |
213 |
|
214 |
*r_dh = dh; |
215 |
return 0; |
216 |
} |
217 |
|
218 |
|
219 |
gpgme_error_t |
220 |
gpgme_data_new_from_filepart (gpgme_data_t *r_dh, const char *fname, FILE *fp, |
221 |
long offset, ulong length) |
222 |
{ |
223 |
gpgme_data_t dh; |
224 |
gpgme_error_t err; |
225 |
|
226 |
if (!r_dh) |
227 |
return mk_error (Invalid_Value); |
228 |
*r_dh = NULL; |
229 |
if ( fname && fp ) /* these are mutual exclusive */ |
230 |
return mk_error (Invalid_Value); |
231 |
if (!fname && !fp) |
232 |
return mk_error (Invalid_Value); |
233 |
if (!length) |
234 |
return mk_error (Invalid_Value); |
235 |
|
236 |
err = gpgme_data_new ( &dh ); |
237 |
if (err) |
238 |
return err; |
239 |
|
240 |
if (!fp) { |
241 |
fp = my_fopen (fname, "rb"); |
242 |
if (!fp) { |
243 |
int save_errno = errno; |
244 |
gpgme_data_release (dh); |
245 |
errno = save_errno; |
246 |
return mk_error (File_Error); |
247 |
} |
248 |
} |
249 |
|
250 |
if ( fseek ( fp, offset, SEEK_SET) ) { |
251 |
int save_errno = errno; |
252 |
if (fname) |
253 |
fclose (fp); |
254 |
gpgme_data_release (dh); |
255 |
errno = save_errno; |
256 |
return mk_error (File_Error); |
257 |
} |
258 |
|
259 |
|
260 |
dh->private_buffer = malloc ( length? length : 1 ); |
261 |
if( !dh->private_buffer ) { |
262 |
if( fname ) |
263 |
fclose( fp ); |
264 |
gpgme_data_release (dh); |
265 |
return mk_error (Out_Of_Core); |
266 |
} |
267 |
dh->private_len = length; |
268 |
|
269 |
if ( fread ( dh->private_buffer, dh->private_len, 1, fp ) != 1 ) { |
270 |
int save_errno = errno; |
271 |
if (fname) |
272 |
fclose (fp); |
273 |
gpgme_data_release (dh); |
274 |
errno = save_errno; |
275 |
return mk_error (File_Error); |
276 |
} |
277 |
|
278 |
if (fname) |
279 |
fclose (fp); |
280 |
|
281 |
dh->len = dh->private_len; |
282 |
dh->data = dh->private_buffer; |
283 |
dh->writepos = dh->len; |
284 |
dh->type = GPGME_DATA_TYPE_MEM; |
285 |
|
286 |
*r_dh = dh; |
287 |
return 0; |
288 |
} |
289 |
|
290 |
|
291 |
/** |
292 |
* gpgme_data_release: |
293 |
* @dh: Data object |
294 |
* |
295 |
* Release the data object @dh. @dh may be NULL in which case nothing |
296 |
* happens. |
297 |
**/ |
298 |
void |
299 |
gpgme_data_release (gpgme_data_t dh) |
300 |
{ |
301 |
if (dh) { |
302 |
safe_free (dh->private_buffer); |
303 |
safe_free (dh); |
304 |
} |
305 |
} /* gpgme_data_release */ |
306 |
|
307 |
|
308 |
char * |
309 |
_gpgme_data_release_and_return_string (gpgme_data_t dh) |
310 |
{ |
311 |
char *val = NULL; |
312 |
|
313 |
if (!dh) |
314 |
return val; |
315 |
|
316 |
if (!_gpgme_data_append (dh, "", 1)) { /* append EOS */ |
317 |
val = dh->private_buffer; |
318 |
if (!val && dh->data) { |
319 |
val = malloc (dh->len); |
320 |
if (val) |
321 |
memcpy (val, dh->data, dh->len); |
322 |
} |
323 |
} |
324 |
safe_free (dh); |
325 |
return val; |
326 |
} |
327 |
|
328 |
|
329 |
/** |
330 |
* gpgme_data_release_and_get_mem: |
331 |
* @dh: the data object |
332 |
* @r_len: returns the length of the memory |
333 |
* |
334 |
* Release the data object @dh and return its content and the length |
335 |
* of that content. The caller has to free this data. @dh maybe NULL |
336 |
* in which case NULL is returned. If there is not enough memory for |
337 |
* allocating the return value, NULL is returned and the object is |
338 |
* released. |
339 |
* |
340 |
* Return value: a pointer to an allocated buffer of length @r_len. |
341 |
**/ |
342 |
char * |
343 |
gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len) |
344 |
{ |
345 |
char *val = NULL; |
346 |
|
347 |
if (r_len) |
348 |
*r_len = 0; |
349 |
if (dh) { |
350 |
size_t len = dh->len; |
351 |
val = dh->private_buffer; |
352 |
if ( !val && dh->data ) { |
353 |
val = malloc (len); |
354 |
if ( val ) |
355 |
memcpy (val, dh->data, len); |
356 |
} |
357 |
safe_free (dh); |
358 |
if (val && r_len) |
359 |
*r_len = len; |
360 |
} |
361 |
return val; |
362 |
} |
363 |
|
364 |
|
365 |
/** |
366 |
* gpgme_data_get_type: |
367 |
* @dh: the data object |
368 |
* |
369 |
* Get the type of the data object. |
370 |
* Data types are prefixed with %GPGME_DATA_TYPE_ |
371 |
* |
372 |
* Return value: the data type |
373 |
**/ |
374 |
gpgme_data_type_t |
375 |
gpgme_data_get_type ( gpgme_data_t dh ) |
376 |
{ |
377 |
if ( !dh || (!dh->data && !dh->read_cb)) |
378 |
return GPGME_DATA_TYPE_NONE; |
379 |
|
380 |
return dh->type; |
381 |
} |
382 |
|
383 |
void |
384 |
_gpgme_data_set_mode( gpgme_data_t dh, gpgme_data_mode_t mode ) |
385 |
{ |
386 |
assert( dh ); |
387 |
dh->mode = mode; |
388 |
} |
389 |
|
390 |
|
391 |
gpgme_data_mode_t |
392 |
_gpgme_data_get_mode( gpgme_data_t dh ) |
393 |
{ |
394 |
assert( dh ); |
395 |
return dh->mode; |
396 |
} |
397 |
|
398 |
/** |
399 |
* gpgme_data_rewind: |
400 |
* @dh: the data object |
401 |
* |
402 |
* Prepare the data object in a way, that a gpgme_data_read() does start |
403 |
* at the beginning of the data. This has to be done for all types |
404 |
* of data objects. |
405 |
* |
406 |
* Return value: An error code or 0 on success |
407 |
**/ |
408 |
gpgme_error_t |
409 |
gpgme_data_rewind ( gpgme_data_t dh ) |
410 |
{ |
411 |
if ( !dh ) |
412 |
return mk_error (Invalid_Value); |
413 |
|
414 |
if ( dh->type == GPGME_DATA_TYPE_NONE |
415 |
|| dh->type == GPGME_DATA_TYPE_MEM ) { |
416 |
dh->readpos = 0; |
417 |
} |
418 |
else if (dh->type == GPGME_DATA_TYPE_CB) { |
419 |
dh->len = dh->readpos = 0; |
420 |
dh->read_cb_eof = 0; |
421 |
/* FIXME: do a special call to the read function to trigger a rewind |
422 |
there */ |
423 |
} |
424 |
else |
425 |
return mk_error (General_Error); |
426 |
return 0; |
427 |
} |
428 |
|
429 |
/** |
430 |
* gpgme_data_read: |
431 |
* @dh: the data object |
432 |
* @buffer: A buffer |
433 |
* @length: The length of that bufer |
434 |
* @nread: Returns the number of bytes actually read. |
435 |
* |
436 |
* Copy data from the current read position (which may be set by |
437 |
* gpgme_data_rewind()) to the supplied @buffer, max. @length bytes |
438 |
* are copied and the actual number of bytes are returned in @nread. |
439 |
* If there are no more bytes available %GPGME_EOF is returned and @nread |
440 |
* is set to 0. |
441 |
* |
442 |
* Return value: An errorcode or 0 on success, EOF is indcated by the |
443 |
* error code GPGME_EOF. |
444 |
**/ |
445 |
gpgme_error_t |
446 |
gpgme_data_read ( gpgme_data_t dh, char *buffer, size_t length, size_t *nread ) |
447 |
{ |
448 |
size_t nbytes; |
449 |
|
450 |
if ( !dh ) |
451 |
return mk_error (Invalid_Value); |
452 |
if (dh->type == GPGME_DATA_TYPE_MEM ) { |
453 |
nbytes = dh->len - dh->readpos; |
454 |
if ( !nbytes ) { |
455 |
*nread = 0; |
456 |
return mk_error(EOF); |
457 |
} |
458 |
if (nbytes > length) |
459 |
nbytes = length; |
460 |
memcpy ( buffer, dh->data + dh->readpos, nbytes ); |
461 |
*nread = nbytes; |
462 |
dh->readpos += nbytes; |
463 |
} |
464 |
else if (dh->type == GPGME_DATA_TYPE_CB) { |
465 |
nbytes = dh->len - dh->readpos; |
466 |
if ( nbytes ) { |
467 |
/* we have unread data - return this */ |
468 |
if (nbytes > length) |
469 |
nbytes = length; |
470 |
memcpy ( buffer, dh->data + dh->readpos, nbytes ); |
471 |
*nread = nbytes; |
472 |
dh->readpos += nbytes; |
473 |
} |
474 |
else { /* get the data from the callback */ |
475 |
if (!dh->read_cb || dh->read_cb_eof) { |
476 |
*nread = 0; |
477 |
return mk_error (EOF); |
478 |
} |
479 |
if (dh->read_cb (dh->read_cb_value, buffer, length, nread )) { |
480 |
*nread = 0; |
481 |
dh->read_cb_eof = 1; |
482 |
return mk_error (EOF); |
483 |
} |
484 |
} |
485 |
} |
486 |
else |
487 |
return mk_error (General_Error); |
488 |
return 0; |
489 |
} |
490 |
|
491 |
|
492 |
gpgme_error_t |
493 |
_gpgme_data_eof( gpgme_data_t dh ) |
494 |
{ |
495 |
if( !dh ) |
496 |
return mk_error( Invalid_Value ); |
497 |
if( dh->type == GPGME_DATA_TYPE_MEM ) { |
498 |
size_t nbytes = dh->len - dh->readpos; |
499 |
if( !nbytes ) |
500 |
return mk_error( EOF ); |
501 |
} |
502 |
return 0; |
503 |
} |
504 |
|
505 |
|
506 |
gpgme_error_t |
507 |
_gpgme_data_unread (gpgme_data_t dh, const char *buffer, size_t length ) |
508 |
{ |
509 |
if( !dh ) |
510 |
return mk_error (Invalid_Value); |
511 |
if( dh->type == GPGME_DATA_TYPE_MEM ) { |
512 |
/* check that we don't unread more than we have yet read */ |
513 |
if( dh->readpos < length ) |
514 |
return mk_error( Invalid_Value ); |
515 |
/* No need to use the buffer for this data type */ |
516 |
dh->readpos -= length; |
517 |
} |
518 |
else { |
519 |
return mk_error( General_Error ); |
520 |
} |
521 |
return 0; |
522 |
} |
523 |
|
524 |
|
525 |
/* |
526 |
* This function does make sense when we know that it contains no nil chars. |
527 |
*/ |
528 |
char * |
529 |
_gpgme_data_get_as_string ( gpgme_data_t dh ) |
530 |
{ |
531 |
char *val = NULL; |
532 |
|
533 |
if (dh) { |
534 |
val = malloc ( dh->len+1 ); |
535 |
if ( val ) { |
536 |
memcpy ( val, dh->data, dh->len ); |
537 |
val[dh->len] = 0; |
538 |
} |
539 |
} |
540 |
return val; |
541 |
} |
542 |
|
543 |
|
544 |
/** |
545 |
* gpgme_data_write: |
546 |
* @dh: the context |
547 |
* @buffer: data to be written to the data object |
548 |
* @length: length o this data |
549 |
* |
550 |
* Write the content of @buffer to the data object @dh at the current write |
551 |
* position. |
552 |
* |
553 |
* Return value: 0 on succress or an errorcode |
554 |
**/ |
555 |
gpgme_error_t |
556 |
gpgme_data_write (gpgme_data_t dh, const char *buffer, size_t length) |
557 |
{ |
558 |
if (!dh || !buffer) |
559 |
return mk_error (Invalid_Value); |
560 |
|
561 |
return _gpgme_data_append (dh, buffer, length ); |
562 |
} |
563 |
|
564 |
|
565 |
gpgme_error_t |
566 |
_gpgme_data_append ( gpgme_data_t dh, const char *buffer, size_t length ) |
567 |
{ |
568 |
assert (dh); |
569 |
|
570 |
if ( dh->type == GPGME_DATA_TYPE_NONE ) { |
571 |
/* convert it to a mem data type */ |
572 |
assert (!dh->private_buffer); |
573 |
dh->type = GPGME_DATA_TYPE_MEM; |
574 |
dh->private_len = length < ALLOC_CHUNK? ALLOC_CHUNK : length; |
575 |
dh->private_buffer = malloc ( dh->private_len ); |
576 |
if( !dh->private_buffer ) { |
577 |
dh->private_len = 0; |
578 |
return mk_error (Out_Of_Core); |
579 |
} |
580 |
dh->writepos = 0; |
581 |
dh->data = dh->private_buffer; |
582 |
} |
583 |
else if ( dh->type != GPGME_DATA_TYPE_MEM ) |
584 |
return mk_error (Invalid_Type); |
585 |
|
586 |
if ( dh->mode != GPGME_DATA_MODE_INOUT |
587 |
&& dh->mode != GPGME_DATA_MODE_IN ) |
588 |
return mk_error (Invalid_Mode); |
589 |
|
590 |
if ( !dh->private_buffer ) { |
591 |
/* we have to copy it now */ |
592 |
assert (dh->data); |
593 |
dh->private_len = dh->len+length; |
594 |
if (dh->private_len < ALLOC_CHUNK) |
595 |
dh->private_len = ALLOC_CHUNK; |
596 |
dh->private_buffer = malloc ( dh->private_len ); |
597 |
if (!dh->private_buffer) { |
598 |
dh->private_len = 0; |
599 |
return mk_error (Out_Of_Core); |
600 |
} |
601 |
memcpy ( dh->private_buffer, dh->data, dh->len ); |
602 |
dh->writepos = dh->len; |
603 |
dh->data = dh->private_buffer; |
604 |
} |
605 |
|
606 |
/* allocate more memory if needed */ |
607 |
if ( dh->writepos + length > dh->private_len ) { |
608 |
char *p; |
609 |
size_t newlen = dh->private_len |
610 |
+ (dh->len < ALLOC_CHUNK? ALLOC_CHUNK : length); |
611 |
p = realloc ( dh->private_buffer, newlen ); |
612 |
if ( !p ) |
613 |
return mk_error (Out_Of_Core); |
614 |
dh->private_buffer = p; |
615 |
dh->private_len = newlen; |
616 |
dh->data = dh->private_buffer; |
617 |
assert ( !(dh->writepos + length > dh->private_len) ); |
618 |
} |
619 |
|
620 |
memcpy ( dh->private_buffer + dh->writepos, buffer, length ); |
621 |
dh->writepos += length; |
622 |
dh->len += length; |
623 |
|
624 |
return 0; |
625 |
} |
626 |
|
627 |
gpgme_error_t |
628 |
_gpgme_data_append_string ( gpgme_data_t dh, const char *s ) |
629 |
{ |
630 |
return _gpgme_data_append ( dh, s, s? strlen(s):0 ); |
631 |
} |
632 |
|
633 |
|
634 |
gpgme_error_t |
635 |
_gpgme_data_read_from_tmpfile( gpgme_data_t dh ) |
636 |
{ |
637 |
FILE *fp; |
638 |
size_t n; |
639 |
unsigned char buf[512]; |
640 |
|
641 |
gpgme_data_rewind( dh ); |
642 |
fp = fopen( _gpgme_get_tmpfile(0), "rb" ); |
643 |
if( fp == NULL ) |
644 |
return mk_error( File_Error ); |
645 |
while( !feof(fp) ) { |
646 |
memset(buf, 0, sizeof buf ); |
647 |
n = fread(buf, 1, sizeof buf - 1, fp ); |
648 |
if( n > 0 ) |
649 |
gpgme_data_write( dh, buf, n ); |
650 |
} |
651 |
fclose( fp ); |
652 |
return 0; |
653 |
} /* _gpgme_data_read_from_tmpfile */ |
654 |
|
655 |
|
656 |
gpgme_error_t |
657 |
_gpgme_data_write_to_tmpfile( gpgme_data_t dh ) |
658 |
{ |
659 |
FILE *fp; |
660 |
char *p; |
661 |
|
662 |
gpgme_data_rewind( dh ); |
663 |
fp = fopen( _gpgme_get_tmpfile(1), "wb" ); |
664 |
if( fp == NULL ) |
665 |
return mk_error( File_Error ); |
666 |
p = _gpgme_data_get_as_string( dh ); |
667 |
if( p ) { |
668 |
fwrite( p, 1, strlen( p ), fp ); |
669 |
safe_free( p ); |
670 |
} |
671 |
fclose( fp ); |
672 |
return 0; |
673 |
} /* _gpgme_data_write_to_tmpfile */ |
674 |
|
675 |
char* |
676 |
gpgme_data_get_as_string( gpgme_data_t dh ) |
677 |
{ |
678 |
return _gpgme_data_get_as_string( dh ); |
679 |
} /* gpgme_data_get_as_string */ |
680 |
|
681 |
char* |
682 |
gpgme_data_release_and_return_string( gpgme_data_t dh ) |
683 |
{ |
684 |
return _gpgme_data_release_and_return_string( dh ); |
685 |
} /* gpgme_data_release_and_return_string */ |
686 |
|
687 |
gpgme_error_t |
688 |
gpgme_data_release_and_set_file (gpgme_data_t dh, const char *fname) |
689 |
{ |
690 |
char *p = NULL; |
691 |
FILE *fp; |
692 |
|
693 |
fp = my_fopen (fname, "wb"); |
694 |
if (fp == NULL) |
695 |
return mk_error (File_Error); |
696 |
|
697 |
p = _gpgme_data_release_and_return_string (dh); |
698 |
if (p) { |
699 |
fwrite (p, 1, strlen (p), fp); |
700 |
fflush (fp); |
701 |
memset (p, 0xFF, strlen (p)); |
702 |
safe_free (p); |
703 |
} |
704 |
fclose (fp); |
705 |
return 0; |
706 |
} /* gpgme_data_release_and_set_file */ |
707 |
|
708 |
|
709 |
size_t |
710 |
gpgme_data_readline( gpgme_data_t dh, char * line, size_t nbytes ) |
711 |
{ |
712 |
char ch = 0; |
713 |
size_t nread = 0, pos = 0; |
714 |
|
715 |
if( !dh ) |
716 |
return 0; |
717 |
|
718 |
memset( line, 0, nbytes ); |
719 |
while( !gpgme_data_read( dh, &ch, 1, &nread ) ) { |
720 |
if( !nread ) |
721 |
break; |
722 |
if( ch == '\n' ) { |
723 |
line[pos++] = ch; |
724 |
line[pos++] = '\0'; |
725 |
break; |
726 |
} |
727 |
line[pos++] = ch; |
728 |
if( pos > nbytes ) { |
729 |
line[pos++] = '\0'; |
730 |
break; |
731 |
} |
732 |
} |
733 |
|
734 |
return pos; |
735 |
} /* gpgme_data_readline */ |
736 |
|
737 |
|
738 |
static char* |
739 |
wrap_lines_soft( char *buf, int wraplen ) |
740 |
{ |
741 |
char *curpos, *lastspc, *lastbrk; |
742 |
|
743 |
for( curpos = lastspc = lastbrk = buf; *curpos; curpos++ ) { |
744 |
if( *curpos == ' ' ) |
745 |
lastspc = curpos; |
746 |
else { |
747 |
if( *curpos == '\n' ) { |
748 |
lastbrk = curpos; |
749 |
lastspc = lastbrk; |
750 |
} |
751 |
} |
752 |
if( (curpos - lastbrk) >= wraplen ) { |
753 |
*lastspc = '\n'; |
754 |
lastbrk = lastspc; |
755 |
} |
756 |
} |
757 |
|
758 |
return buf; |
759 |
} /* wrap_lines_soft */ |
760 |
|
761 |
static char* |
762 |
wrap_lines( char *buf, size_t bufsize, size_t wraplen ) |
763 |
{ |
764 |
char *soft, *hard, *p; |
765 |
size_t pos = 0, size = 0; |
766 |
|
767 |
soft = wrap_lines_soft( buf, wraplen ); |
768 |
if( !soft ) |
769 |
return NULL; |
770 |
hard = malloc (bufsize + (bufsize/10)); |
771 |
if( !hard ) |
772 |
return NULL; |
773 |
strcpy (hard, soft); |
774 |
while( soft ) { |
775 |
p = strchr( soft, '\n' ); |
776 |
if( p == NULL ) |
777 |
break; |
778 |
pos = p - soft + 1; |
779 |
if( soft[pos-2] != '\r' ) { |
780 |
memcpy( hard + size, soft, pos-1 ); |
781 |
size += (pos-1); |
782 |
memcpy( hard + size, "\r\n", 2 ); |
783 |
size += 2; |
784 |
} |
785 |
else { |
786 |
memcpy( hard+size, soft, pos ); |
787 |
size += pos; |
788 |
} |
789 |
soft += pos; |
790 |
} |
791 |
|
792 |
memcpy( hard + size, "\0", 1 ); |
793 |
return hard; |
794 |
} /* wrap_lines */ |
795 |
|
796 |
|
797 |
int |
798 |
gpgme_data_wrap_lines( gpgme_data_t *r_dh, size_t wraplen ) |
799 |
{ |
800 |
gpgme_error_t err = 0; |
801 |
gpgme_data_t mdh; |
802 |
char *raw, *p; |
803 |
size_t nlen; |
804 |
|
805 |
err = gpgme_data_new( &mdh ); |
806 |
if( err ) |
807 |
return err; |
808 |
|
809 |
raw = _gpgme_data_get_as_string( *r_dh ); |
810 |
if( !raw ) { |
811 |
gpgme_data_release( mdh ); |
812 |
return mk_error( General_Error ); |
813 |
} |
814 |
nlen = strlen( raw ); |
815 |
if( !strchr( raw, '\n' ) && nlen < wraplen ) { |
816 |
gpgme_data_release( mdh ); |
817 |
safe_free( raw ); |
818 |
return 0; |
819 |
} |
820 |
|
821 |
p = wrap_lines( raw, nlen, wraplen ); |
822 |
if( p ) |
823 |
_gpgme_data_append_string( mdh, p ); |
824 |
gpgme_data_release( *r_dh ); |
825 |
*r_dh = mdh; |
826 |
safe_free( raw ); |
827 |
safe_free( p ); |
828 |
return 0; |
829 |
} /* gpgme_data_wrap_lines */ |
830 |
|
831 |
|
832 |
gpgme_error_t |
833 |
gpgme_data_mail_quote (gpgme_data_t *r_dh) |
834 |
{ |
835 |
gpgme_data_t dh; |
836 |
char buf[128]; |
837 |
|
838 |
if (!*r_dh) |
839 |
return mk_error (Invalid_Value); |
840 |
gpgme_data_new (&dh); |
841 |
while (gpgme_data_readline (*r_dh, buf, 127)) { |
842 |
gpgme_data_write (dh, "> ", 2); |
843 |
gpgme_data_write (dh, buf, strlen (buf)); |
844 |
} |
845 |
gpgme_data_release (*r_dh); |
846 |
*r_dh = dh; |
847 |
return 0; |
848 |
} |
849 |
|
850 |
|
851 |
gpgme_error_t |
852 |
gpgme_data_extract_plaintext( gpgme_data_t sig, gpgme_data_t *r_plain ) |
853 |
{ |
854 |
gpgme_data_t plain; |
855 |
gpgme_error_t err; |
856 |
char line[128+32]; |
857 |
int pos = 0; |
858 |
int sig_begin = 0; |
859 |
|
860 |
err = gpgme_data_new( &plain ); |
861 |
if( err ) { |
862 |
if( r_plain ) |
863 |
*r_plain = NULL; |
864 |
return err; |
865 |
} |
866 |
|
867 |
while( gpgme_data_readline( sig, line, 128 ) ) { |
868 |
if( !strncmp( line, "-----BEGIN PGP SIGNED MESSAGE", 29 ) |
869 |
|| !strncmp( line, "Version:", 8 ) |
870 |
|| !strncmp( line, "Comment:", 8 ) |
871 |
|| !strncmp( line, "Charset:", 8 ) |
872 |
|| !strncmp( line, "Hash:", 5 ) |
873 |
|| !strncmp (line, "MessageID", 9)) |
874 |
continue; |
875 |
if( strlen( line ) <= 2 ) |
876 |
break; /* parsed all headers, now we reached the body */ |
877 |
} |
878 |
/* fixme: handle multi dash escaped sequences! */ |
879 |
while( gpgme_data_readline( sig, line, 128 ) ) { |
880 |
if( !strncmp( line, "-----BEGIN PGP SIGNATURE", 24 ) ) |
881 |
break; /* end of plaintext */ |
882 |
if( !strncmp( line, "- -", 3 ) ) |
883 |
pos = 2; |
884 |
_gpgme_data_append_string( plain, line + pos ); |
885 |
pos = 0; |
886 |
} |
887 |
if( r_plain ) |
888 |
*r_plain = plain; |
889 |
else |
890 |
gpgme_data_release( plain ); |
891 |
return err; |
892 |
} /* gpgme_data_extract_plaintext */ |
893 |
|
894 |
|
895 |
gpgme_error_t |
896 |
gpgme_data_change_version( gpgme_data_t *r_dh ) |
897 |
{ |
898 |
gpgme_error_t err = 0; |
899 |
gpgme_data_t mdh; |
900 |
char line[128+32]; |
901 |
|
902 |
err = gpgme_data_new( &mdh ); |
903 |
if( err ) { |
904 |
if( r_dh ) |
905 |
*r_dh = NULL; |
906 |
return err; |
907 |
} |
908 |
while( gpgme_data_readline( *r_dh, line, 128 ) ) { |
909 |
if( strlen( line ) > 14 |
910 |
&& !strncmp( line, "Version: GnuPG", 14 ) |
911 |
&& !strstr( line, pgm_string ) ) { |
912 |
line[strlen( line ) - 2] = '\0'; |
913 |
strcat( line, " - " ); |
914 |
strcat( line, pgm_string ); |
915 |
strcat( line, "\r\n" ); |
916 |
} |
917 |
_gpgme_data_append_string( mdh, line ); |
918 |
} |
919 |
gpgme_data_release( *r_dh ); |
920 |
if( r_dh ) |
921 |
*r_dh = mdh; |
922 |
else |
923 |
gpgme_data_release( mdh ); |
924 |
return err; |
925 |
} /* gpgme_data_change_version */ |
926 |
|
927 |
|
928 |
/* Convert two hexadecimal digits from STR to the value they |
929 |
represent. Returns -1 if one of the characters is not a |
930 |
hexadecimal digit. */ |
931 |
static int |
932 |
_gpgme_hextobyte (const unsigned char *str) |
933 |
{ |
934 |
int val = 0; |
935 |
int i; |
936 |
|
937 |
#define NROFHEXDIGITS 2 |
938 |
for (i = 0; i < NROFHEXDIGITS; i++) { |
939 |
if (*str >= '0' && *str <= '9') |
940 |
val += *str - '0'; |
941 |
else if (*str >= 'A' && *str <= 'F') |
942 |
val += 10 + *str - 'A'; |
943 |
else if (*str >= 'a' && *str <= 'f') |
944 |
val += 10 + *str - 'a'; |
945 |
else |
946 |
return -1; |
947 |
if (i < NROFHEXDIGITS - 1) |
948 |
val *= 16; |
949 |
str++; |
950 |
} |
951 |
return val; |
952 |
} |
953 |
|
954 |
|
955 |
/* Decode the C formatted string SRC and store the result in the |
956 |
buffer *DESTP which is LEN bytes long. If LEN is zero, then a |
957 |
large enough buffer is allocated with malloc and *DESTP is set to |
958 |
the result. Currently, LEN is only used to specify if allocation |
959 |
is desired or not, the caller is expected to make sure that *DESTP |
960 |
is large enough if LEN is not zero. */ |
961 |
gpgme_error_t |
962 |
_gpgme_decode_c_string (const char *src, char **destp, size_t len) |
963 |
{ |
964 |
char *dest; |
965 |
|
966 |
/* Set up the destination buffer. */ |
967 |
if (len) |
968 |
{ |
969 |
if (len < strlen (src) + 1) |
970 |
return GPGME_General_Error; |
971 |
|
972 |
dest = *destp; |
973 |
} |
974 |
else |
975 |
{ |
976 |
/* The converted string will never be larger than the original |
977 |
string. */ |
978 |
dest = malloc (strlen (src) + 1); |
979 |
if (!dest) |
980 |
return GPGME_Out_Of_Core; |
981 |
*destp = dest; |
982 |
} |
983 |
|
984 |
/* Convert the string. */ |
985 |
while (*src) |
986 |
{ |
987 |
if (*src != '\\') |
988 |
{ |
989 |
*(dest++) = *(src++); |
990 |
continue; |
991 |
} |
992 |
|
993 |
switch (src[1]) |
994 |
{ |
995 |
#define DECODE_ONE(match,result) \ |
996 |
case match: \ |
997 |
src += 2; \ |
998 |
*(dest++) = result; \ |
999 |
break; |
1000 |
|
1001 |
DECODE_ONE ('\'', '\''); |
1002 |
DECODE_ONE ('\"', '\"'); |
1003 |
DECODE_ONE ('\?', '\?'); |
1004 |
DECODE_ONE ('\\', '\\'); |
1005 |
DECODE_ONE ('a', '\a'); |
1006 |
DECODE_ONE ('b', '\b'); |
1007 |
DECODE_ONE ('f', '\f'); |
1008 |
DECODE_ONE ('n', '\n'); |
1009 |
DECODE_ONE ('r', '\r'); |
1010 |
DECODE_ONE ('t', '\t'); |
1011 |
DECODE_ONE ('v', '\v'); |
1012 |
|
1013 |
case 'x': |
1014 |
{ |
1015 |
int val = _gpgme_hextobyte (&src[2]); |
1016 |
|
1017 |
if (val == -1) |
1018 |
{ |
1019 |
/* Should not happen. */ |
1020 |
*(dest++) = *(src++); |
1021 |
*(dest++) = *(src++); |
1022 |
if (*src) |
1023 |
*(dest++) = *(src++); |
1024 |
if (*src) |
1025 |
*(dest++) = *(src++); |
1026 |
} |
1027 |
else |
1028 |
{ |
1029 |
if (!val) |
1030 |
{ |
1031 |
/* A binary zero is not representable in a C |
1032 |
string. */ |
1033 |
*(dest++) = '\\'; |
1034 |
*(dest++) = '0'; |
1035 |
} |
1036 |
else |
1037 |
*((unsigned char *) dest++) = val; |
1038 |
src += 4; |
1039 |
} |
1040 |
} |
1041 |
|
1042 |
default: |
1043 |
{ |
1044 |
/* Should not happen. */ |
1045 |
*(dest++) = *(src++); |
1046 |
*(dest++) = *(src++); |
1047 |
} |
1048 |
} |
1049 |
} |
1050 |
*(dest++) = 0; |
1051 |
|
1052 |
return 0; |
1053 |
} |
1054 |
|
1055 |
|
1056 |
void |
1057 |
gpgme_set_pgm_string (const char * name) |
1058 |
{ |
1059 |
if (!name || !*name) |
1060 |
return; |
1061 |
memset (pgm_string, 0, sizeof pgm_string); |
1062 |
strncpy (pgm_string, name, sizeof pgm_string-1); |
1063 |
} /* gpgme_set_pgm_string */ |