35bf8024431c89290b6f738e201696df1364e932
[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 /* Get the current encoding meta information. */
469 GpgmeDataEncoding
470 gpgme_data_get_encoding (GpgmeData dh)
471 {
472   return dh? dh->encoding : GPGME_DATA_ENCODING_NONE;
473 }
474
475 /* Set the encoding meta information for DB to ENC */
476 GpgmeError
477 gpgme_data_set_encoding (GpgmeData dh, GpgmeDataEncoding enc)
478 {
479   if (!dh)
480     return GPGME_Invalid_Value;
481   if (enc < 0 || enc > GPGME_DATA_ENCODING_ARMOR)
482     return GPGME_Invalid_Value;
483   dh->encoding = enc;
484   return 0;
485 }
486
487 void 
488 _gpgme_data_set_mode (GpgmeData dh, GpgmeDataMode mode)
489 {
490   assert (dh);
491   dh->mode = mode;
492 }
493
494
495 GpgmeDataMode
496 _gpgme_data_get_mode (GpgmeData dh)
497 {
498   assert (dh);
499   return dh->mode;
500 }
501
502
503 /**
504  * gpgme_data_rewind:
505  * @dh: the data object 
506  * 
507  * Prepare the data object in a way, that a gpgme_data_read() does start
508  * at the beginning of the data.  This has to be done for all types
509  * of data objects.
510  * 
511  * Return value: An error code or 0 on success
512  **/
513 GpgmeError
514 gpgme_data_rewind (GpgmeData dh)
515 {
516   if (!dh)
517     return mk_error (Invalid_Value);
518
519   switch (dh->type)
520     {
521     case GPGME_DATA_TYPE_NONE:
522     case GPGME_DATA_TYPE_MEM:
523       dh->readpos = 0;
524       return 0;
525
526     case GPGME_DATA_TYPE_CB:
527       dh->len = dh->readpos = 0;
528       dh->read_cb_eof = 0;
529       if (dh->read_cb (dh->read_cb_value, NULL, 0, NULL))
530         return mk_error (Not_Implemented);
531       return 0;
532
533     default:
534       return mk_error (General_Error);
535     }
536 }
537
538 /**
539  * gpgme_data_read:
540  * @dh: the data object
541  * @buffer: A buffer 
542  * @length: The length of that bufer
543  * @nread: Returns the number of bytes actually read.
544  * 
545  * Copy data from the current read position (which may be set by
546  * gpgme_data_rewind()) to the supplied @buffer, max. @length bytes
547  * are copied and the actual number of bytes are returned in @nread.
548  * If there are no more bytes available %GPGME_EOF is returned and @nread
549  * is set to 0.
550  *
551  * With a @buffer of NULL, the function does only return the number of
552  * bytes available and does not move the read pointer.  This does only
553  * work for certain data types, all other will respond with an
554  * %GPGME_Invalid_Type.
555  * 
556  * Return value: An error code or 0 on success, EOF is indcated by the
557  * error code GPGME_EOF.
558  **/
559 GpgmeError
560 gpgme_data_read (GpgmeData dh, void *buffer, size_t length, size_t *nread)
561 {
562   size_t nbytes;
563
564   if (!dh)
565     return mk_error (Invalid_Value);
566   
567   switch (dh->type)
568     {
569     case GPGME_DATA_TYPE_MEM:
570       nbytes = dh->len - dh->readpos;
571       if (!nbytes)
572         {
573           *nread = 0;
574           return mk_error(EOF);
575         }
576
577       if (!buffer)
578         *nread = nbytes;
579       else
580         {
581           if (nbytes > length)
582             nbytes = length;
583           memcpy (buffer, dh->data + dh->readpos, nbytes);
584           *nread = nbytes;
585           dh->readpos += nbytes;
586         }
587       return 0;
588     
589     case GPGME_DATA_TYPE_CB:
590       if (!buffer)
591         {
592           *nread = 0;
593           return mk_error (Invalid_Type);
594         }
595       nbytes = dh->len - dh->readpos;
596       if (nbytes)
597         {
598           /* We have unread data - return this.  */
599           if (nbytes > length)
600             nbytes = length;
601           memcpy (buffer, dh->data + dh->readpos, nbytes);
602           *nread = nbytes;
603           dh->readpos += nbytes;
604         }
605       else
606         {
607           /* Get the data from the callback.  */
608           if (!dh->read_cb || dh->read_cb_eof)
609             { 
610               *nread = 0;
611               return mk_error (EOF);
612             }
613           if (dh->read_cb (dh->read_cb_value, buffer, length, nread))
614             {
615               *nread = 0;
616               dh->read_cb_eof = 1;
617               return mk_error (EOF);
618             }
619         }
620       return 0;
621       
622     default:
623       return mk_error (General_Error);
624     }
625
626
627
628 GpgmeError
629 _gpgme_data_unread (GpgmeData dh, const char *buffer, size_t length)
630 {
631    if (!dh)
632      return mk_error (Invalid_Value);
633
634    if (dh->type == GPGME_DATA_TYPE_MEM)
635      {
636        /* Check that we don't unread more than we have yet read.  */
637        if (dh->readpos < length)
638          return mk_error (Invalid_Value);
639        /* No need to use the buffer for this data type.  */
640        dh->readpos -= length;
641      }
642    else
643      return mk_error (General_Error);
644
645    return 0;
646 }
647
648
649 /* 
650  * This function does make sense when we know that it contains no nil chars.
651  */
652 char *
653 _gpgme_data_get_as_string (GpgmeData dh)
654 {
655   char *val = NULL;
656
657   if (dh)
658     {
659       val = xtrymalloc (dh->len+1);
660       if (val)
661         {
662           memcpy (val, dh->data, dh->len);
663           val[dh->len] = 0;
664         }
665     }
666   return val;
667 }
668
669
670 /**
671  * gpgme_data_write:
672  * @dh: the context
673  * @buffer: data to be written to the data object
674  * @length: length of this data
675  * 
676  * Write the content of @buffer to the data object @dh at the current write
677  * position. 
678  * 
679  * Return value: 0 on success or an error code
680  **/
681 GpgmeError
682 gpgme_data_write (GpgmeData dh, const void *buffer, size_t length)
683 {
684   if (!dh || !buffer)
685     return mk_error (Invalid_Value);
686       
687   return _gpgme_data_append (dh, (const char *)buffer, length );
688 }
689
690
691 GpgmeError
692 _gpgme_data_append (GpgmeData dh, const char *buffer, size_t length)
693 {
694   assert (dh);
695
696   if (dh->type == GPGME_DATA_TYPE_NONE)
697     {
698       /* Convert it to a mem data type.  */
699       assert (!dh->private_buffer);
700       dh->type = GPGME_DATA_TYPE_MEM;
701       dh->private_len = length < ALLOC_CHUNK? ALLOC_CHUNK : length;
702       dh->private_buffer = xtrymalloc (dh->private_len);
703       if (!dh->private_buffer)
704         {
705           dh->private_len = 0;
706           return mk_error (Out_Of_Core);
707         }
708       dh->writepos = 0;
709       dh->data = dh->private_buffer;
710     }
711   else if (dh->type != GPGME_DATA_TYPE_MEM)
712     return mk_error (Invalid_Type);
713     
714   if (dh->mode != GPGME_DATA_MODE_INOUT 
715       && dh->mode != GPGME_DATA_MODE_IN)
716     return mk_error (Invalid_Mode);
717
718   if (!dh->private_buffer)
719     {
720       /* We have to copy it now.  */
721       assert (dh->data);
722       dh->private_len = dh->len+length;
723       if (dh->private_len < ALLOC_CHUNK)
724         dh->private_len = ALLOC_CHUNK;
725       dh->private_buffer = xtrymalloc (dh->private_len);
726       if (!dh->private_buffer)
727         {
728           dh->private_len = 0;
729           return mk_error (Out_Of_Core);
730         }
731       memcpy (dh->private_buffer, dh->data, dh->len);
732       dh->writepos = dh->len;
733       dh->data = dh->private_buffer;
734     }
735
736     /* Allocate more memory if needed.  */
737   if (dh->writepos + length > dh->private_len)
738     {
739       char *p;
740       size_t newlen = dh->private_len
741         + (length < ALLOC_CHUNK? ALLOC_CHUNK : length);
742       p = xtryrealloc (dh->private_buffer, newlen);
743       if (!p) 
744         return mk_error (Out_Of_Core);
745       dh->private_buffer = p;
746       dh->private_len = newlen;
747       dh->data = dh->private_buffer;
748       assert (!(dh->writepos + length > dh->private_len));
749     }
750
751   memcpy (dh->private_buffer + dh->writepos, buffer, length);
752   dh->writepos += length;
753   dh->len += length;
754
755   return 0;
756 }
757
758
759 GpgmeError
760 _gpgme_data_append_string (GpgmeData dh, const char *s)
761 {
762   return _gpgme_data_append (dh, s, s ? strlen(s) : 0);
763 }
764
765
766 GpgmeError
767 _gpgme_data_append_for_xml (GpgmeData dh,
768                             const char *buffer, size_t len)
769 {
770   const char *text, *s;
771   size_t n;
772   int rc = 0; 
773        
774   if (!dh || !buffer)
775     return mk_error (Invalid_Value);
776
777   do
778     {
779       for (text=NULL, s = buffer, n = len; n && !text; s++, n--)
780         {
781           if (*s == '<') 
782             text = "&lt;";
783           else if (*s == '>')
784             text = "&gt;";  /* Not sure whether this is really needed.  */
785           else if (*s == '&')
786             text = "&amp;";
787           else if (!*s)
788             text = "&#00;";
789         }
790       if (text)
791         {
792           s--;
793           n++;
794         }
795       if (s != buffer) 
796         rc = _gpgme_data_append (dh, buffer, s-buffer);
797       if (!rc && text)
798         {
799           rc = _gpgme_data_append_string (dh, text);
800           s++;
801           n--;
802         }
803       buffer = s;
804       len = n;
805     }
806   while (!rc && len);
807   return rc;
808 }
809
810
811 /*
812  * Append a string to DATA and convert it so that the result will be 
813  * valid XML. 
814  */
815 GpgmeError
816 _gpgme_data_append_string_for_xml (GpgmeData dh, const char *string)
817 {
818   return _gpgme_data_append_for_xml (dh, string, strlen (string));
819 }
820
821
822 static int
823 hextobyte(const byte *s)
824 {
825   int c;
826
827   if (*s >= '0' && *s <= '9')
828     c = 16 * (*s - '0');
829   else if (*s >= 'A' && *s <= 'F')
830     c = 16 * (10 + *s - 'A');
831   else if (*s >= 'a' && *s <= 'f')
832     c = 16 * (10 + *s - 'a');
833   else
834     return -1;
835   s++;
836   if (*s >= '0' && *s <= '9')
837     c += *s - '0';
838   else if (*s >= 'A' && *s <= 'F')
839     c += 10 + *s - 'A';
840   else if (*s >= 'a' && *s <= 'f')
841     c += 10 + *s - 'a';
842   else
843     return -1;
844   return c;
845 }
846
847 /* 
848  * Append a string with percent style (%XX) escape characters as XML.
849  */
850 GpgmeError
851 _gpgme_data_append_percentstring_for_xml (GpgmeData dh, const char *string)
852 {
853   const byte *s;
854   byte *buf, *d;
855   int val;
856   GpgmeError err;
857
858   d = buf = xtrymalloc (strlen (string));
859   for (s = string; *s; s++)
860     {
861       if (*s == '%' && (val = hextobyte (s+1)) != -1)
862         {
863           *d++ = val;
864           s += 2;
865         }
866       else
867         *d++ = *s;
868     }
869
870   err = _gpgme_data_append_for_xml (dh, buf, d - buf);
871   xfree (buf);
872   return err;
873 }
874
875 /* Functions to support the wait interface.  */
876
877 void
878 _gpgme_data_inbound_handler (void *opaque, int fd)
879 {
880   GpgmeData dh = opaque;
881   GpgmeError err;
882   int nread;
883   char buf[200];
884
885   assert (_gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN);
886
887   nread = _gpgme_io_read (fd, buf, 200);
888   if (nread < 0)
889     {
890       DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
891               fd, nread, strerror (errno) );
892       _gpgme_io_close (fd);     /* XXX ??? */
893       return;
894     }
895   else if (!nread)
896     {
897       _gpgme_io_close (fd);
898       return; /* eof */
899     }
900   /* We could improve this with a GpgmeData function which takes
901    * the read function or provides a memory area for writing to it.
902    */
903     
904   err = _gpgme_data_append (dh, buf, nread);
905   if (err)
906     {
907       DEBUG1 ("_gpgme_append_data failed: %s\n",
908               gpgme_strerror(err));
909       /* Fixme: we should close the pipe or read it to /dev/null in
910        * this case. Returnin EOF is not sufficient */
911       _gpgme_io_close (fd);     /* XXX ??? */
912       return;
913     }
914
915   return;
916 }
917
918 static int
919 write_mem_data (GpgmeData dh, int fd)
920 {
921   size_t nbytes;
922   int nwritten; 
923
924   nbytes = dh->len - dh->readpos;
925   if (!nbytes)
926     {
927       return 1;
928     }
929     
930   /* FIXME: Arggg, the pipe blocks on large write request, although
931    * select told us that it is okay to write - need to figure out
932    * why this happens?  Stevens says nothing about this problem (or
933    * is it my Linux kernel 2.4.0test1)
934    * To avoid that we have set the pipe to nonblocking.
935    */
936
937   nwritten = _gpgme_io_write (fd, dh->data+dh->readpos, nbytes);
938   if (nwritten == -1 && errno == EAGAIN)
939     return 0;
940   if (nwritten < 1)
941     {
942       DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
943               fd, nwritten, strerror (errno));
944       return 1;
945     }
946
947   dh->readpos += nwritten;
948   return 0;
949 }
950
951 static int
952 write_cb_data (GpgmeData dh, int fd)
953 {
954   size_t nbytes;
955   int  err, nwritten; 
956   char buffer[512];
957
958   err = gpgme_data_read (dh, buffer, DIM(buffer), &nbytes);
959   if (err == GPGME_EOF)
960     {
961       return 1;
962     }
963     
964   nwritten = _gpgme_io_write (fd, buffer, nbytes);
965   if (nwritten == -1 && errno == EAGAIN )
966     return 0;
967   if (nwritten < 1)
968     {
969       DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
970               fd, nwritten, strerror (errno));
971       return 1;
972     }
973
974   if (nwritten < nbytes)
975     {
976       /* ugly, ugly: It does currently only for for MEM type data */
977       if (_gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten))
978         DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
979                 nbytes - nwritten);
980       return 1;
981     }
982   
983   return 0;
984 }
985
986 void
987 _gpgme_data_outbound_handler (void *opaque, int fd)
988 {
989   GpgmeData dh = opaque;
990
991   assert (_gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT);
992   switch (gpgme_data_get_type (dh))
993     {
994     case GPGME_DATA_TYPE_MEM:
995       if (write_mem_data (dh, fd))
996         _gpgme_io_close (fd);
997       break;
998     case GPGME_DATA_TYPE_CB:
999       if (write_cb_data (dh, fd))
1000         _gpgme_io_close (fd);
1001       break;
1002     default:
1003       assert (0);
1004     }
1005 }