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