2007-01-18 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     return;
62
63   if (dh->file_name)
64     free (dh->file_name);
65   free (dh);
66 }
67
68 \f
69 /* Read up to SIZE bytes into buffer BUFFER from the data object with
70    the handle DH.  Return the number of characters read, 0 on EOF and
71    -1 on error.  If an error occurs, errno is set.  */
72 ssize_t
73 gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
74 {
75   if (!dh)
76     {
77       errno = EINVAL;
78       return -1;
79     }
80   if (!dh->cbs->read)
81     {
82       errno = ENOSYS;
83       return -1;
84     }
85   return (*dh->cbs->read) (dh, buffer, size);
86 }
87
88
89 /* Write up to SIZE bytes from buffer BUFFER to the data object with
90    the handle DH.  Return the number of characters written, or -1 on
91    error.  If an error occurs, errno is set.  */
92 ssize_t
93 gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
94 {
95   if (!dh)
96     {
97       errno = EINVAL;
98       return -1;
99     }
100   if (!dh->cbs->write)
101     {
102       errno = ENOSYS;
103       return -1;
104     }
105   return (*dh->cbs->write) (dh, buffer, size);
106 }
107
108
109 /* Set the current position from where the next read or write starts
110    in the data object with the handle DH to OFFSET, relativ to
111    WHENCE.  */
112 off_t
113 gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence)
114 {
115   if (!dh)
116     {
117       errno = EINVAL;
118       return -1;
119     }
120   if (!dh->cbs->seek)
121     {
122       errno = ENOSYS;
123       return -1;
124     }
125
126   /* For relative movement, we must take into account the actual
127      position of the read counter.  */
128   if (whence == SEEK_CUR)
129     offset -= dh->pending_len;
130
131   offset = (*dh->cbs->seek) (dh, offset, whence);
132   if (offset >= 0)
133     dh->pending_len = 0;
134
135   return offset;
136 }
137
138
139 /* Release the data object with the handle DH.  */
140 void
141 gpgme_data_release (gpgme_data_t dh)
142 {
143   if (!dh)
144     return;
145
146   if (dh->cbs->release)
147     (*dh->cbs->release) (dh);
148   _gpgme_data_release (dh);
149 }
150
151
152 /* Get the current encoding meta information for the data object with
153    handle DH.  */
154 gpgme_data_encoding_t
155 gpgme_data_get_encoding (gpgme_data_t dh)
156 {
157   return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
158 }
159
160
161 /* Set the encoding meta information for the data object with handle
162    DH to ENC.  */
163 gpgme_error_t
164 gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
165 {
166   if (!dh)
167     return gpg_error (GPG_ERR_INV_VALUE);
168   if (enc < 0 || enc > GPGME_DATA_ENCODING_ARMOR)
169     return gpg_error (GPG_ERR_INV_VALUE);
170   dh->encoding = enc;
171   return 0;
172 }
173
174
175 /* Set the file name associated with the data object with handle DH to
176    FILE_NAME.  */
177 gpgme_error_t
178 gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name)
179 {
180   if (!dh)
181     return gpg_error (GPG_ERR_INV_VALUE);
182
183   if (dh->file_name)
184     free (dh->file_name);
185
186   if (file_name)
187     {
188       dh->file_name = strdup (file_name);
189       if (!dh->file_name)
190         return gpg_error_from_errno (errno);
191     }
192   else
193     dh->file_name = 0;
194
195   return 0;
196 }
197
198 /* Get the file name associated with the data object with handle DH,
199    or NULL if there is none.  */
200 char *
201 gpgme_data_get_file_name (gpgme_data_t dh)
202 {
203   if (!dh)
204     return NULL;
205
206   return dh->file_name;
207 }
208
209 \f
210 /* Functions to support the wait interface.  */
211
212 gpgme_error_t
213 _gpgme_data_inbound_handler (void *opaque, int fd)
214 {
215   gpgme_data_t dh = (gpgme_data_t) opaque;
216   char buffer[BUFFER_SIZE];
217   char *bufp = buffer;
218   ssize_t buflen;
219
220   buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
221   if (buflen < 0)
222     return gpg_error_from_errno (errno);
223   if (buflen == 0)
224     {
225       _gpgme_io_close (fd);
226       return 0;
227     }
228
229   do
230     {
231       ssize_t amt = gpgme_data_write (dh, bufp, buflen);
232       if (amt == 0 || (amt < 0 && errno != EINTR))
233         return gpg_error_from_errno (errno);
234       bufp += amt;
235       buflen -= amt;
236     }
237   while (buflen > 0);
238   return 0;
239 }
240
241
242 gpgme_error_t
243 _gpgme_data_outbound_handler (void *opaque, int fd)
244 {
245   gpgme_data_t dh = (gpgme_data_t) opaque;
246   ssize_t nwritten;
247
248   if (!dh->pending_len)
249     {
250       ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
251       if (amt < 0)
252         return gpg_error_from_errno (errno);
253       if (amt == 0)
254         {
255           _gpgme_io_close (fd);
256           return 0;
257         }
258       dh->pending_len = amt;
259     }
260
261   nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
262   if (nwritten == -1 && errno == EAGAIN)
263     return 0;
264
265   if (nwritten == -1 && errno == EPIPE)
266     {
267       /* Not much we can do.  The other end closed the pipe, but we
268          still have data.  This should only ever happen if the other
269          end is going to tell us what happened on some other channel.
270          Silently close our end.  */
271       _gpgme_io_close (fd);
272       return 0;
273     }
274
275   if (nwritten <= 0)
276     return gpg_error_from_errno (errno);
277
278   if (nwritten < dh->pending_len)
279     memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
280   dh->pending_len -= nwritten;
281   return 0;
282 }
283
284
285 /* Get the file descriptor associated with DH, if possible.  Otherwise
286    return -1.  */
287 int
288 _gpgme_data_get_fd (gpgme_data_t dh)
289 {
290   if (!dh || !dh->cbs->get_fd)
291     return -1;
292   return (*dh->cbs->get_fd) (dh);
293 }