2005-04-14 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / data.c
1 /* data.c - An abstraction for data objects.
2    Copyright (C) 2002, 2003, 2004, 2005 g10 Code GmbH
3
4    This file is part of GPGME.
5  
6    GPGME is free software; you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10    
11    GPGME is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15    
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <string.h>
29
30 #include "gpgme.h"
31 #include "data.h"
32 #include "util.h"
33 #include "ops.h"
34 #include "priv-io.h"
35
36 \f
37 gpgme_error_t
38 _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
39 {
40   gpgme_data_t dh;
41
42   if (!r_dh)
43     return gpg_error (GPG_ERR_INV_VALUE);
44
45   *r_dh = NULL;
46   dh = calloc (1, sizeof (*dh));
47   if (!dh)
48     return gpg_error_from_errno (errno);
49
50   dh->cbs = cbs;
51
52   *r_dh = dh;
53   return 0;
54 }
55
56
57 void
58 _gpgme_data_release (gpgme_data_t dh)
59 {
60   if (dh)
61     free (dh);
62 }
63
64 \f
65 /* Read up to SIZE bytes into buffer BUFFER from the data object with
66    the handle DH.  Return the number of characters read, 0 on EOF and
67    -1 on error.  If an error occurs, errno is set.  */
68 ssize_t
69 gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
70 {
71   if (!dh)
72     {
73       errno = EINVAL;
74       return -1;
75     }
76   if (!dh->cbs->read)
77     {
78       errno = ENOSYS;
79       return -1;
80     }
81   return (*dh->cbs->read) (dh, buffer, size);
82 }
83
84
85 /* Write up to SIZE bytes from buffer BUFFER to the data object with
86    the handle DH.  Return the number of characters written, or -1 on
87    error.  If an error occurs, errno is set.  */
88 ssize_t
89 gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
90 {
91   if (!dh)
92     {
93       errno = EINVAL;
94       return -1;
95     }
96   if (!dh->cbs->write)
97     {
98       errno = ENOSYS;
99       return -1;
100     }
101   return (*dh->cbs->write) (dh, buffer, size);
102 }
103
104
105 /* Set the current position from where the next read or write starts
106    in the data object with the handle DH to OFFSET, relativ to
107    WHENCE.  */
108 off_t
109 gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence)
110 {
111   if (!dh)
112     {
113       errno = EINVAL;
114       return -1;
115     }
116   if (!dh->cbs->seek)
117     {
118       errno = ENOSYS;
119       return -1;
120     }
121
122   /* For relative movement, we must take into account the actual
123      position of the read counter.  */
124   if (whence == SEEK_CUR)
125     offset -= dh->pending_len;
126
127   offset = (*dh->cbs->seek) (dh, offset, whence);
128   if (offset >= 0)
129     dh->pending_len = 0;
130
131   return offset;
132 }
133
134
135 /* Release the data object with the handle DH.  */
136 void
137 gpgme_data_release (gpgme_data_t dh)
138 {
139   if (!dh)
140     return;
141
142   if (dh->cbs->release)
143     (*dh->cbs->release) (dh);
144   _gpgme_data_release (dh);
145 }
146
147
148 /* Get the current encoding meta information for the data object with
149    handle DH.  */
150 gpgme_data_encoding_t
151 gpgme_data_get_encoding (gpgme_data_t dh)
152 {
153   return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
154 }
155
156
157 /* Set the encoding meta information for the data object with handle
158    DH to ENC.  */
159 gpgme_error_t
160 gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
161 {
162   if (!dh)
163     return gpg_error (GPG_ERR_INV_VALUE);
164   if (enc < 0 || enc > GPGME_DATA_ENCODING_ARMOR)
165     return gpg_error (GPG_ERR_INV_VALUE);
166   dh->encoding = enc;
167   return 0;
168 }
169
170 \f
171 /* Functions to support the wait interface.  */
172
173 gpgme_error_t
174 _gpgme_data_inbound_handler (void *opaque, int fd)
175 {
176   gpgme_data_t dh = (gpgme_data_t) opaque;
177   char buffer[BUFFER_SIZE];
178   char *bufp = buffer;
179   ssize_t buflen;
180
181   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
182   if (buflen < 0)
183     return gpg_error_from_errno (errno);
184   if (buflen == 0)
185     {
186       _gpgme_io_close (fd);
187       return 0;
188     }
189
190   do
191     {
192       ssize_t amt = gpgme_data_write (dh, bufp, buflen);
193       if (amt == 0 || (amt < 0 && errno != EINTR))
194         return gpg_error_from_errno (errno);
195       bufp += amt;
196       buflen -= amt;
197     }
198   while (buflen > 0);
199   return 0;
200 }
201
202
203 gpgme_error_t
204 _gpgme_data_outbound_handler (void *opaque, int fd)
205 {
206   gpgme_data_t dh = (gpgme_data_t) opaque;
207   ssize_t nwritten;
208
209   if (!dh->pending_len)
210     {
211       ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
212       if (amt < 0)
213         return gpg_error_from_errno (errno);
214       if (amt == 0)
215         {
216           _gpgme_io_close (fd);
217           return 0;
218         }
219       dh->pending_len = amt;
220     }
221
222   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
223   if (nwritten == -1 && errno == EAGAIN)
224     return 0;
225
226   if (nwritten == -1 && errno == EPIPE)
227     {
228       /* Not much we can do.  The other end closed the pipe, but we
229          still have data.  This should only ever happen if the other
230          end is going to tell us what happened on some other channel.
231          Silently close our end.  */
232       _gpgme_io_close (fd);
233       return 0;
234     }
235
236   if (nwritten <= 0)
237     return gpg_error_from_errno (errno);
238
239   if (nwritten < dh->pending_len)
240     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
241   dh->pending_len -= nwritten;
242   return 0;
243 }