1805d58fd8cf016e41f42e017f6a75569e8153e1
[gpgme.git] / gpgme / data.c
1 /* data.c
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001, 2002 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME 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  * GPGME 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 <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30
31 #include "util.h"
32 #include "context.h"
33 #include "ops.h"
34 #include "io.h"
35
36 /* When expanding an internal buffer, always extend it by ALLOC_CHUNK
37    bytes at a time.  */
38 #define ALLOC_CHUNK 1024
39
40
41 /**
42  * gpgme_data_new:
43  * @r_dh: returns the new data object 
44  * 
45  * Create a new data object without any content. 
46  * 
47  * Return value: An error value or 0 on success
48  **/
49 GpgmeError
50 gpgme_data_new (GpgmeData *r_dh)
51 {
52   GpgmeData dh;
53
54   if (!r_dh)
55     return mk_error (Invalid_Value);
56   *r_dh = NULL;
57
58   dh = xtrycalloc (1, sizeof *dh);
59   if (!dh)
60     return mk_error (Out_Of_Core);
61
62   dh->mode = GPGME_DATA_MODE_INOUT; 
63
64   *r_dh = dh;
65   return 0;
66 }
67
68
69 /**
70  * gpgme_data_new_from_mem:
71  * @r_dh:   Returns a new data object.
72  * @buffer: Initialize with this.
73  * @size: Size of the buffer
74  * @copy: Flag wether a copy of the buffer should be used.
75  * 
76  * Create a new data object and initialize with data from the memory.
77  * A @copy with value %TRUE creates a copy of the memory, a value of
78  * %FALSE uses the original memory of @buffer and the caller has to
79  * make sure that this buffer is valid until gpgme_data_release() is
80  * called.
81  * 
82  * Return value: An error value or 0 for success.
83  **/
84 GpgmeError
85 gpgme_data_new_from_mem (GpgmeData *r_dh, const char *buffer, size_t size,
86                          int copy)
87 {
88   GpgmeData dh;
89   GpgmeError err;
90
91   if (!r_dh)
92     return mk_error (Invalid_Value);
93   *r_dh = NULL;
94   if (!buffer)
95     return mk_error (Invalid_Value);
96
97   err = gpgme_data_new (&dh);
98   if (err)
99     return err;
100
101   dh->type = GPGME_DATA_TYPE_MEM;
102   dh->len = size;
103   if (!copy)
104     dh->data = buffer;
105   else
106     {
107       dh->private_buffer = xtrymalloc (size);
108       if (!dh->private_buffer)
109         {
110           gpgme_data_release (dh);
111           return mk_error (Out_Of_Core);
112         }
113       dh->private_len = size;
114       memcpy (dh->private_buffer, buffer, size);
115       dh->data = dh->private_buffer;
116       dh->writepos = size;
117     }
118
119   *r_dh = dh;
120   return 0;
121 }
122
123
124 /**
125  * gpgme_data_new_with_read_cb:
126  * @r_dh: returns the new data object
127  * @read_cb: callback function
128  * @read_cb_value: value passed to the callback function
129  * 
130  * Create a new data object which is a wrapper around the callback function.
131  * The callback function is defined as:
132  * <literal>
133  * typedef int (*read_cb) (void *cb_value,
134  *                         char *buffer,
135  *                         size_t count,
136  *                         size_t *nread);
137  * </literal>
138  *
139  * The callback should return a maximium of @count bytes in @buffer
140  * and the number actually read in @nread.  It may return 0 in @nread
141  * if there are no bytes currently available.  To indicate EOF the
142  * function should return with an error code of %-1 and set @nread to
143  * 0.  The callback may support passing %NULL for @buffer and @nread
144  * and %0 for count as an indication to reset its internal read
145  * pointer.
146  *
147  * Return value: An error value or 0 for success.
148  **/
149 GpgmeError
150 gpgme_data_new_with_read_cb (GpgmeData *r_dh,
151                              int (*read_cb) (void *,char *, size_t ,size_t *),
152                              void *read_cb_value)
153 {
154   GpgmeData dh;
155   GpgmeError err;
156
157   if (!r_dh)
158     return mk_error (Invalid_Value);
159   *r_dh = NULL;
160
161   if (!read_cb)
162     return mk_error (Invalid_Value);
163
164   err = gpgme_data_new (&dh);
165   if (err)
166     return err;
167
168   dh->type = GPGME_DATA_TYPE_CB;
169   dh->mode = GPGME_DATA_MODE_OUT;
170   dh->read_cb = read_cb;
171   dh->read_cb_value = read_cb_value;
172     
173   *r_dh = dh;
174   return 0;
175 }
176
177
178 /**
179  * gpgme_data_new_from_file:
180  * @r_dh: returns the new data object
181  * @fname: filename
182  * @copy: Flag, whether the file should be copied.
183  * 
184  * Create a new data object and initialize it with the content of 
185  * the file @file.  If @copy is %True the file is immediately read in
186  * and closed.  @copy of %False is not yet supportted.
187  * 
188  * Return value: An error code or 0 on success. If the error code is
189  * %GPGME_File_Error, the OS error code is held in %errno.
190  **/
191 GpgmeError
192 gpgme_data_new_from_file (GpgmeData *r_dh, const char *fname, int copy)
193 {
194   GpgmeData dh;
195   GpgmeError err;
196   struct stat st;
197   FILE *fp;
198
199   if (!r_dh)
200     return mk_error (Invalid_Value);
201   *r_dh = NULL;
202   if (!fname)
203     return mk_error (Invalid_Value);
204
205   /* We only support copy for now.  In future we might want to honor
206      the copy flag and just store a file pointer.  */
207   if (!copy)
208     return mk_error (Not_Implemented);
209
210   err = gpgme_data_new (&dh);
211   if (err)
212     return err;
213
214   fp = fopen (fname, "rb");
215   if (!fp)
216     {
217       int save_errno = errno;
218       gpgme_data_release (dh);
219       errno = save_errno;
220       return mk_error (File_Error);
221     }
222
223   if (fstat(fileno(fp), &st))
224     {
225       int save_errno = errno;
226       fclose (fp);
227       gpgme_data_release (dh);
228       errno = save_errno;
229       return mk_error (File_Error);
230     }
231
232   /* We should check the length of the file and don't allow for too
233      large files.  */
234   dh->private_buffer = xtrymalloc (st.st_size);
235   if (!dh->private_buffer)
236     {
237       fclose (fp);
238       gpgme_data_release (dh);
239       return mk_error (Out_Of_Core);
240     }
241   dh->private_len = st.st_size;
242
243   while (fread (dh->private_buffer, dh->private_len, 1, fp) < 1
244          && ferror (fp) && errno == EINTR);
245
246   if (ferror (fp))
247     {
248       int save_errno = errno;
249       fclose (fp);
250       gpgme_data_release (dh);
251       errno = save_errno;
252       return mk_error (File_Error);
253     }
254
255   fclose (fp);
256
257   dh->type = GPGME_DATA_TYPE_MEM;
258   dh->len = dh->private_len;
259   dh->data = dh->private_buffer;
260   dh->writepos = dh->len;
261     
262   *r_dh = dh;
263   return 0;
264 }
265
266
267 /**
268  * gpgme_data_new_from_filepart:
269  * @r_dh: returns the new data object
270  * @fname: filename
271  * @fp: filepointer
272  * @offset: Start reading at this offset
273  * @length: Read this many bytes 
274  * 
275  * Create a new data object and initialize it with @length bytes
276  * starting at @offset of @file or @fp.  Either a filename or an open
277  * filepointer may be given.
278  *
279  *
280  * Return value: An error code or 0 on success. If the error code is
281  * %GPGME_File_Error, the OS error code is held in %errno.
282  **/
283 GpgmeError
284 gpgme_data_new_from_filepart (GpgmeData *r_dh, const char *fname, FILE *fp,
285                               off_t offset, size_t length)
286 {
287   GpgmeData dh;
288   GpgmeError err;
289   int save_errno = 0;
290
291   if (!r_dh)
292     return mk_error (Invalid_Value);
293   *r_dh = NULL;
294
295   if ((fname && fp) || (!fname && !fp))
296     return mk_error (Invalid_Value);
297
298   err = gpgme_data_new (&dh);
299   if (err)
300     return err;
301
302   if (!length)
303     goto out;
304
305   if (fname)
306     {
307       fp = fopen (fname, "rb");
308       if (!fp)
309         {
310           err = mk_error (File_Error);
311           goto out;
312         }
313     }
314
315   if (fseek (fp, (long) offset, SEEK_SET))
316     {
317       err = mk_error (File_Error);
318       goto out;
319     }
320
321   dh->private_buffer = xtrymalloc (length);
322   if (!dh->private_buffer)
323     {
324       err = mk_error (Out_Of_Core);
325       goto out;
326     }
327   dh->private_len = length;
328   
329   while (fread (dh->private_buffer, dh->private_len, 1, fp) < 1
330          && ferror (fp) && errno == EINTR);
331
332   if (ferror (fp))
333     {
334       err = mk_error (File_Error);
335       goto out;
336     }
337       
338   dh->type = GPGME_DATA_TYPE_MEM;
339   dh->len = dh->private_len;
340   dh->data = dh->private_buffer;
341   dh->writepos = dh->len;
342
343  out:
344   if (err)
345     save_errno = errno;
346
347   if (fname && fp)
348     fclose (fp);
349
350   if (err)
351     {
352       gpgme_data_release (dh);
353       errno = save_errno;
354     }
355   else
356     *r_dh = dh;
357   return err;
358 }
359
360
361 /**
362  * gpgme_data_release:
363  * @dh: Data object 
364  * 
365  * Release the data object @dh.  @dh may be NULL in which case nothing
366  * happens.
367  **/
368 void
369 gpgme_data_release (GpgmeData dh)
370 {
371   if (dh)
372     {
373       xfree (dh->private_buffer); 
374       xfree (dh);
375     }
376 }
377
378
379 /*
380  * Release the data object @dh.  @dh may be NULL in which case nothing
381  * happens.
382  * 
383  * Return value: An allocated memory object with the content of the
384  * data object.  The function makes sure that the returned string can
385  * safely be accessed using the string fucntions.
386  **/
387 char *
388 _gpgme_data_release_and_return_string (GpgmeData dh)
389 {
390   char *val = NULL;
391
392   if (dh)
393     {
394       if (_gpgme_data_append (dh, "", 1)) /* append EOS */
395         xfree (dh->private_buffer );
396       else
397         {
398           val = dh->private_buffer;
399           if (!val && dh->data)
400             {
401               val = xtrymalloc (dh->len);
402               if (val)
403                 memcpy (val, dh->data, dh->len);
404             }
405         }
406       xfree (dh);
407     }
408   return val;
409 }
410
411
412 /**
413  * gpgme_data_release_and_get_mem:
414  * @dh: the data object
415  * @r_len: returns the length of the memory
416  * 
417  * Release the data object @dh and return its content and the length
418  * of that content.  The caller has to free this data.  @dh maybe NULL
419  * in which case NULL is returned.  If there is not enough memory for
420  * allocating the return value, NULL is returned and the object is
421  * released.
422  * 
423  * Return value: a pointer to an allocated buffer of length @r_len.
424  **/
425 char *
426 gpgme_data_release_and_get_mem (GpgmeData dh, size_t *r_len)
427 {
428   char *val = NULL;
429
430   if (r_len)
431     *r_len = 0;
432   if (dh)
433     {
434       size_t len = dh->len;
435       val = dh->private_buffer;
436       if (!val && dh->data)
437         {
438           val = xtrymalloc (len);
439           if (val)
440             memcpy (val, dh->data, len);
441         }
442       xfree (dh);
443       if (val && r_len)
444         *r_len = len;
445     }
446   return val;
447 }
448
449
450 /**
451  * gpgme_data_get_type:
452  * @dh: the data object
453  * 
454  * Get the type of the data object.
455  * Data types are prefixed with %GPGME_DATA_TYPE_
456  * 
457  * Return value: the data type
458  **/
459 GpgmeDataType
460 gpgme_data_get_type (GpgmeData dh)
461 {
462   if (!dh || (!dh->data && !dh->read_cb))
463     return GPGME_DATA_TYPE_NONE;
464
465   return dh->type;
466 }
467
468
469 void 
470 _gpgme_data_set_mode (GpgmeData dh, GpgmeDataMode mode)
471 {
472   assert (dh);
473   dh->mode = mode;
474 }
475
476
477 GpgmeDataMode
478 _gpgme_data_get_mode (GpgmeData dh)
479 {
480   assert (dh);
481   return dh->mode;
482 }
483
484
485 /**
486  * gpgme_data_rewind:
487  * @dh: the data object 
488  * 
489  * Prepare the data object in a way, that a gpgme_data_read() does start
490  * at the beginning of the data.  This has to be done for all types
491  * of data objects.
492  * 
493  * Return value: An error code or 0 on success
494  **/
495 GpgmeError
496 gpgme_data_rewind (GpgmeData dh)
497 {
498   if (!dh)
499     return mk_error (Invalid_Value);
500
501   switch (dh->type)
502     {
503     case GPGME_DATA_TYPE_NONE:
504     case GPGME_DATA_TYPE_MEM:
505       dh->readpos = 0;
506       return 0;
507
508     case GPGME_DATA_TYPE_CB:
509       dh->len = dh->readpos = 0;
510       dh->read_cb_eof = 0;
511       if (dh->read_cb (dh->read_cb_value, NULL, 0, NULL))
512         return mk_error (Not_Implemented);
513       return 0;
514
515     default:
516       return mk_error (General_Error);
517     }
518 }
519
520 /**
521  * gpgme_data_read:
522  * @dh: the data object
523  * @buffer: A buffer 
524  * @length: The length of that bufer
525  * @nread: Returns the number of bytes actually read.
526  * 
527  * Copy data from the current read position (which may be set by
528  * gpgme_data_rewind()) to the supplied @buffer, max. @length bytes
529  * are copied and the actual number of bytes are returned in @nread.
530  * If there are no more bytes available %GPGME_EOF is returned and @nread
531  * is set to 0.
532  *
533  * With a @buffer of NULL, the function does only return the number of
534  * bytes available and does not move the read pointer.  This does only
535  * work for certain data types, all other will respond with an
536  * %GPGME_Invalid_Type.
537  * 
538  * Return value: An error code or 0 on success, EOF is indcated by the
539  * error code GPGME_EOF.
540  **/
541 GpgmeError
542 gpgme_data_read (GpgmeData dh, char *buffer, size_t length, size_t *nread)
543 {
544   size_t nbytes;
545
546   if (!dh)
547     return mk_error (Invalid_Value);
548   
549   switch (dh->type)
550     {
551     case GPGME_DATA_TYPE_MEM:
552       nbytes = dh->len - dh->readpos;
553       if (!nbytes)
554         {
555           *nread = 0;
556           return mk_error(EOF);
557         }
558
559       if (!buffer)
560         *nread = nbytes;
561       else
562         {
563           if (nbytes > length)
564             nbytes = length;
565           memcpy (buffer, dh->data + dh->readpos, nbytes);
566           *nread = nbytes;
567           dh->readpos += nbytes;
568         }
569       return 0;
570     
571     case GPGME_DATA_TYPE_CB:
572       if (!buffer)
573         {
574           *nread = 0;
575           return mk_error (Invalid_Type);
576         }
577       nbytes = dh->len - dh->readpos;
578       if (nbytes)
579         {
580           /* We have unread data - return this.  */
581           if (nbytes > length)
582             nbytes = length;
583           memcpy (buffer, dh->data + dh->readpos, nbytes);
584           *nread = nbytes;
585           dh->readpos += nbytes;
586         }
587       else
588         {
589           /* Get the data from the callback.  */
590           if (!dh->read_cb || dh->read_cb_eof)
591             { 
592               *nread = 0;
593               return mk_error (EOF);
594             }
595           if (dh->read_cb (dh->read_cb_value, buffer, length, nread))
596             {
597               *nread = 0;
598               dh->read_cb_eof = 1;
599               return mk_error (EOF);
600             }
601         }
602       return 0;
603       
604     default:
605       return mk_error (General_Error);
606     }
607
608
609
610 GpgmeError
611 _gpgme_data_unread (GpgmeData dh, const char *buffer, size_t length)
612 {
613    if (!dh)
614      return mk_error (Invalid_Value);
615
616    if (dh->type == GPGME_DATA_TYPE_MEM)
617      {
618        /* Check that we don't unread more than we have yet read.  */
619        if (dh->readpos < length)
620          return mk_error (Invalid_Value);
621        /* No need to use the buffer for this data type.  */
622        dh->readpos -= length;
623      }
624    else
625      return mk_error (General_Error);
626
627    return 0;
628 }
629
630
631 /* 
632  * This function does make sense when we know that it contains no nil chars.
633  */
634 char *
635 _gpgme_data_get_as_string (GpgmeData dh)
636 {
637   char *val = NULL;
638
639   if (dh)
640     {
641       val = xtrymalloc (dh->len+1);
642       if (val)
643         {
644           memcpy (val, dh->data, dh->len);
645           val[dh->len] = 0;
646         }
647     }
648   return val;
649 }
650
651
652 /**
653  * gpgme_data_write:
654  * @dh: the context
655  * @buffer: data to be written to the data object
656  * @length: length of this data
657  * 
658  * Write the content of @buffer to the data object @dh at the current write
659  * position. 
660  * 
661  * Return value: 0 on success or an error code
662  **/
663 GpgmeError
664 gpgme_data_write (GpgmeData dh, const char *buffer, size_t length)
665 {
666   if (!dh || !buffer)
667     return mk_error (Invalid_Value);
668       
669   return _gpgme_data_append (dh, buffer, length );
670 }
671
672
673 GpgmeError
674 _gpgme_data_append (GpgmeData dh, const char *buffer, size_t length)
675 {
676   assert (dh);
677
678   if (dh->type == GPGME_DATA_TYPE_NONE)
679     {
680       /* Convert it to a mem data type.  */
681       assert (!dh->private_buffer);
682       dh->type = GPGME_DATA_TYPE_MEM;
683       dh->private_len = length < ALLOC_CHUNK? ALLOC_CHUNK : length;
684       dh->private_buffer = xtrymalloc (dh->private_len);
685       if (!dh->private_buffer)
686         {
687           dh->private_len = 0;
688           return mk_error (Out_Of_Core);
689         }
690       dh->writepos = 0;
691       dh->data = dh->private_buffer;
692     }
693   else if (dh->type != GPGME_DATA_TYPE_MEM)
694     return mk_error (Invalid_Type);
695     
696   if (dh->mode != GPGME_DATA_MODE_INOUT 
697       && dh->mode != GPGME_DATA_MODE_IN)
698     return mk_error (Invalid_Mode);
699
700   if (!dh->private_buffer)
701     {
702       /* We have to copy it now.  */
703       assert (dh->data);
704       dh->private_len = dh->len+length;
705       if (dh->private_len < ALLOC_CHUNK)
706         dh->private_len = ALLOC_CHUNK;
707       dh->private_buffer = xtrymalloc (dh->private_len);
708       if (!dh->private_buffer)
709         {
710           dh->private_len = 0;
711           return mk_error (Out_Of_Core);
712         }
713       memcpy (dh->private_buffer, dh->data, dh->len);
714       dh->writepos = dh->len;
715       dh->data = dh->private_buffer;
716     }
717
718     /* Allocate more memory if needed.  */
719   if (dh->writepos + length > dh->private_len)
720     {
721       char *p;
722       size_t newlen = dh->private_len
723         + (length < ALLOC_CHUNK? ALLOC_CHUNK : length);
724       p = xtryrealloc (dh->private_buffer, newlen);
725       if (!p) 
726         return mk_error (Out_Of_Core);
727       dh->private_buffer = p;
728       dh->private_len = newlen;
729       dh->data = dh->private_buffer;
730       assert (!(dh->writepos + length > dh->private_len));
731     }
732
733   memcpy (dh->private_buffer + dh->writepos, buffer, length);
734   dh->writepos += length;
735   dh->len += length;
736
737   return 0;
738 }
739
740
741 GpgmeError
742 _gpgme_data_append_string (GpgmeData dh, const char *s)
743 {
744   return _gpgme_data_append (dh, s, s ? strlen(s) : 0);
745 }
746
747
748 GpgmeError
749 _gpgme_data_append_for_xml (GpgmeData dh,
750                             const char *buffer, size_t len)
751 {
752   const char *text, *s;
753   size_t n;
754   int rc = 0; 
755        
756   if (!dh || !buffer)
757     return mk_error (Invalid_Value);
758
759   do
760     {
761       for (text=NULL, s = buffer, n = len; n && !text; s++, n--)
762         {
763           if (*s == '<') 
764             text = "&lt;";
765           else if (*s == '>')
766             text = "&gt;";  /* Not sure whether this is really needed.  */
767           else if (*s == '&')
768             text = "&amp;";
769           else if (!*s)
770             text = "&#00;";
771         }
772       if (text)
773         {
774           s--;
775           n++;
776         }
777       if (s != buffer) 
778         rc = _gpgme_data_append (dh, buffer, s-buffer);
779       if (!rc && text)
780         {
781           rc = _gpgme_data_append_string (dh, text);
782           s++;
783           n--;
784         }
785       buffer = s;
786       len = n;
787     }
788   while (!rc && len);
789   return rc;
790 }
791
792
793 /*
794  * Append a string to DATA and convert it so that the result will be 
795  * valid XML. 
796  */
797 GpgmeError
798 _gpgme_data_append_string_for_xml (GpgmeData dh, const char *string)
799 {
800   return _gpgme_data_append_for_xml (dh, string, strlen (string));
801 }
802
803
804 static int
805 hextobyte(const byte *s)
806 {
807   int c;
808
809   if (*s >= '0' && *s <= '9')
810     c = 16 * (*s - '0');
811   else if (*s >= 'A' && *s <= 'F')
812     c = 16 * (10 + *s - 'A');
813   else if (*s >= 'a' && *s <= 'f')
814     c = 16 * (10 + *s - 'a');
815   else
816     return -1;
817   s++;
818   if (*s >= '0' && *s <= '9')
819     c += *s - '0';
820   else if (*s >= 'A' && *s <= 'F')
821     c += 10 + *s - 'A';
822   else if (*s >= 'a' && *s <= 'f')
823     c += 10 + *s - 'a';
824   else
825     return -1;
826   return c;
827 }
828
829 /* 
830  * Append a string with percent style (%XX) escape characters as XML.
831  */
832 GpgmeError
833 _gpgme_data_append_percentstring_for_xml (GpgmeData dh, const char *string)
834 {
835   const byte *s;
836   byte *buf, *d;
837   int val;
838   GpgmeError err;
839
840   d = buf = xtrymalloc (strlen (string));
841   for (s = string; *s; s++)
842     {
843       if (*s == '%' && (val = hextobyte (s+1)) != -1)
844         {
845           *d++ = val;
846           s += 2;
847         }
848       else
849         *d++ = *s;
850     }
851
852   err = _gpgme_data_append_for_xml (dh, buf, d - buf);
853   xfree (buf);
854   return err;
855 }
856
857 /* Functions to support the wait interface.  */
858
859 int
860 _gpgme_data_inbound_handler (void *opaque, int pid, int fd)
861 {
862   GpgmeData dh = opaque;
863   GpgmeError err;
864   int nread;
865   char buf[200];
866
867   assert (_gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN);
868
869   nread = _gpgme_io_read (fd, buf, 200);
870   if (nread < 0)
871     {
872       DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
873               fd, nread, strerror (errno) );
874       return 1;
875     }
876   else if (!nread)
877     return 1; /* eof */
878
879   /* We could improve this with a GpgmeData function which takes
880    * the read function or provides a memory area for writing to it.
881    */
882     
883   err = _gpgme_data_append (dh, buf, nread);
884   if (err)
885     {
886       DEBUG1 ("_gpgme_append_data failed: %s\n",
887               gpgme_strerror(err));
888       /* Fixme: we should close the pipe or read it to /dev/null in
889        * this case. Returnin EOF is not sufficient */
890       return 1;
891     }
892
893   return 0;
894 }
895
896 static int
897 write_mem_data (GpgmeData dh, int fd)
898 {
899   size_t nbytes;
900   int nwritten; 
901
902   nbytes = dh->len - dh->readpos;
903   if (!nbytes)
904     {
905       _gpgme_io_close (fd);
906       return 1;
907     }
908     
909   /* FIXME: Arggg, the pipe blocks on large write request, although
910    * select told us that it is okay to write - need to figure out
911    * why this happens?  Stevens says nothing about this problem (or
912    * is it my Linux kernel 2.4.0test1)
913    * To avoid that we have set the pipe to nonblocking.
914    */
915
916   nwritten = _gpgme_io_write (fd, dh->data+dh->readpos, nbytes);
917   if (nwritten == -1 && errno == EAGAIN)
918     return 0;
919   if (nwritten < 1)
920     {
921       DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
922               fd, nwritten, strerror (errno));
923       _gpgme_io_close (fd);
924       return 1;
925     }
926
927   dh->readpos += nwritten;
928   return 0;
929 }
930
931 static int
932 write_cb_data (GpgmeData dh, int fd)
933 {
934   size_t nbytes;
935   int  err, nwritten; 
936   char buffer[512];
937
938   err = gpgme_data_read (dh, buffer, DIM(buffer), &nbytes);
939   if (err == GPGME_EOF)
940     {
941       _gpgme_io_close (fd);
942       return 1;
943     }
944     
945   nwritten = _gpgme_io_write (fd, buffer, nbytes);
946   if (nwritten == -1 && errno == EAGAIN )
947     return 0;
948   if (nwritten < 1)
949     {
950       DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
951               fd, nwritten, strerror (errno));
952       _gpgme_io_close (fd);
953       return 1;
954     }
955
956   if (nwritten < nbytes)
957     {
958       /* ugly, ugly: It does currently only for for MEM type data */
959       if (_gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten))
960         DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
961                 nbytes - nwritten);
962       _gpgme_io_close (fd);
963       return 1;
964     }
965   
966   return 0;
967 }
968
969 int
970 _gpgme_data_outbound_handler (void *opaque, int pid, int fd)
971 {
972   GpgmeData dh = opaque;
973
974   assert (_gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT);
975   switch (gpgme_data_get_type (dh))
976     {
977     case GPGME_DATA_TYPE_MEM:
978       if (write_mem_data (dh, fd))
979         return 1; /* ready */
980       break;
981     case GPGME_DATA_TYPE_CB:
982       if (write_cb_data (dh, fd))
983         return 1; /* ready */
984       break;
985     default:
986       assert (0);
987     }
988   
989   return 0;
990 }